Downcasting многомерных массивов Swift
Я пытаюсь уменьшить значение свойства многомерного массива, которое требуется протоколом в подклассе класса, соответствующего протоколу. Однако в настоящее время компилятор выдает мне ошибку, когда я это делаю. Ошибка: 'DataClass' is not identical to 'Any'
,
Странно то, что когда свойство сводится к одномерному массиву, ошибка исчезает. Может ли это быть ошибкой в Swift или я не понимаю, как Swift обрабатывает типизацию многомерных массивов?
Это происходит со времен Swift 1.0, поэтому я чувствую, что упускаю что-то очевидное здесь...
Я воспроизвел мою ситуацию в легко тестируемом фрагменте кода:
protocol MyProtocol {
var myProperty: ([[Any]])! { get set }
func myFuncReturn() -> Any
func myFuncParam(param: Any)
}
class MyClass: MyProtocol {
var myProperty: ([[Any]])!
init(myProperty: ([[Any]])!) {
self.myProperty = myProperty
}
func myFuncReturn() -> Any {
return myProperty[0][0]
}
func myFuncParam(param: Any) { }
}
class MySubclass: MyClass {
var myPropertyOver: ([[DataClass]])! {
return myProperty as? ([[DataClass]])
}
init() {
super.init(myProperty: [[DataClass()]])
}
}
class DataClass { }
Спасибо за вашу помощь!
1 ответ
Проблема только в том, что вы не достаточно конкретны в отношении того, что должно произойти. Допустим, у вас есть массив массивов, и некоторые из них имеют DataClass, а некоторые нет. Что теперь? Вы должны объяснить это в своем коде.
Когда вы произносите, скажем, [AnyObject]
в [Int]
это просто стенография. На самом деле происходит то, что Swift циклически перебирает весь массив и проверяет, может ли каждый элемент быть приведен к Int.
Но то, что вы хотите сделать, это то, для чего нет стенографии. Действительно, для меня (и, следовательно, для Свифта) далеко не очевидно, что вы хотите делать. Вы должны быть явными.
Рассмотрим этот вариант. Мы можем свести весь пример к этому простому случаю:
var arr = [[AnyObject]]()
arr = [[1],[2]]
var arr2 = [[AnyObject]]()
arr2 = [[1],["howdy"]]
Теперь я предполагаю, что вам нужно следующее: если каждый массив в данном массиве является массивом, который может быть приведен к [Int]
, сделай это. Если нет, то вы должны получить ноль: попытка не удалась.
Хорошо, так что если это то, что вы хотите, это то, что вы должны сделать. Для этого нет волшебных сокращений. Так, например:
func cast(array:[[AnyObject]]) -> [[Int]]? {
let result = array.map {
(subarr:[AnyObject]) -> [Int]? in
if let subarr = subarr as? [Int] {
return subarr
} else {
return nil
}
}
var foundnil = false
for subarr in result {
if subarr == nil {
foundnil = true
break
}
}
if foundnil {
return nil
}
return result.map{$0!}
}
И вот доказательство того, что он работает правильно:
cast(arr) // [[1], [2]]
cast(arr2) // nil
Если я не понял, какой результат вы ожидаете, просто измените cast
функция, чтобы получить ожидаемый результат. Но в этом весь смысл; не совсем понятно, чего ты хочешь. Вы не можете просто бросить бросок на эту вещь и ожидать, что это будет иметь значение, или чтобы Свифт прочитал ваши мысли. Вы должны сказать, что вы хотите.