#ios #generics #swift
#iOS #дженерики #быстрый
Вопрос:
Я пишу некоторый Swift-код, где у меня есть массив, содержащий универсальный тип:
let _data: Array<T> = T[]()
Позже в моем коде мне нужно определить тип, хранящийся в массиве. Я попытался использовать метод приведения типов, описанный в документации (хотя он не использовался для дженериков).
switch self._data {
case let doubleData as Array<Double>:
// Do something with doubleData
case let floatData as Array<Float>:
// Do something with floatData
default:
return nil // If the data type is unknown return nil
}
Приведенный выше оператор switch приводит к следующей ошибке при компиляции:
- При излучении ИК-функции SIL @_TFC19Adder_Example__Mac6Matrix9transposeUS_7Элемент__fGS0_Q__FT_GSqGS0_Q___ для «транспонирования» в /code.viperscience/Сумматор / src/ Библиотека сумматоров /Matrix.swift:45:3 :0: ошибка: невозможно выполнить команду: ошибка сегментации: 11:0: ошибка: сбой команды интерфейса swift из-за сигнала (используйте -v, чтобы увидеть вызов) Команда / Applications/Xcode6-Beta2.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr / bin / swift не удалась с кодом выхода 254
Кто-нибудь знает, как я могу привести свои общие данные к их фактическому типу, чтобы предпринять конкретные действия?
Комментарии:
1. Попробуйте использовать
as?
, но я думаю, что в вашем случае это ошибка компилятора … сообщите об этом!2. Я попробовал необязательный, но он не сработал. Я согласен, что это, вероятно, ошибка компилятора. Это не первый случай, который я видел, связанный с дженериками…
Ответ №1:
В swift as
operator — это что-то вроде dynamic_cast
C , которое можно использовать для приведения объекта вниз.
Допустим, у вас есть объект a
типа A
, и вы можете писать let a as B
только тогда, когда type B
идентичен type A
или B
является подклассом A
.
В вашем случае, по-видимому Array<T>
, не всегда может быть приведено к Array<Double>
или Array<Float>
, поэтому компилятор сообщает об ошибках.
Простое решение — сначала преобразовать AnyObject
в, а затем уменьшить до Array<Double>
или Array<Float>
:
let anyData: AnyObject = self._data;
switch anyData {
case let doubleData as? Array<Double>: // use as? operator, instead of as,
// to avoid runtime exception
// Do something with doubleData
case let floatData as? Array<Float>:
// Do something with floatData
default:
return nil // If the data type is unknown return nil
Комментарии:
1. Спасибо за помощь, но я безрезультатно попробовал ваше решение, хотя ваше объяснение было полезным. Я понимаю, что Array<T> не всегда может быть преобразован в Array<Float> или Array<Double>, но разве не для этого предназначен оператор switch? Это действительно не должно иметь значения… Я думаю, что это ошибка компилятора. Кроме того, использование оператора As? только генерирует другую ошибку. В документации Apple (см. Мою Ссылку Выше) не используется оператор As?, а только оператор As.
Ответ №2:
Предположим, у вас есть массив кнопок:
let views: [NSView] = [NSButton(), NSButton(), NSButton()]
Вы можете использовать эти приведения:
let viewsAreButtons = views is [NSButton] // returns true
let buttonsForSure = views as! [NSButton] // crashes if you are wrong
let buttonsMaybe = views as? [NSButton] // optionally set
Если вы попытаетесь использовать as в случае переключения, как показано ниже, это не сработает. Компилятор (Swift 1.2 Xcode 6.3b1) сообщает: «Шаблон понижения типа [NSButton] не может быть использован».
switch views {
case let buttons as [NSButton]:
println("Buttons")
default:
println("something else")
}
Назовите это ограничением. Создайте радар с вашим вариантом использования. Команда Swift действительно старается прислушиваться к отзывам. Если вы действительно хотите, чтобы это работало, вы можете определить свой собственный оператор сопоставления с образцом. В этом случае это было бы что-то вроде этого:
struct ButtonArray { }
let isButtonArray = ButtonArray()
func ~=(pattern: ButtonArray, value: [NSView]) -> Bool {
return value is [NSButton]
}
Тогда это работает:
switch views {
case isButtonArray:
println("Buttons") // This gets printed.
default:
println("something else")
}
Попробуйте это на игровой площадке. Надеюсь, это поможет!