Swift:将Any转换为协议对象数组

And*_* H. 15 casting protocols swift

有一个协议:

protocol Valuable {
    func value() -> Int
}
Run Code Online (Sandbox Code Playgroud)

和一个实现协议的类:

class Value: Valuable {
    private let v: Int

    init(value: Int) {
        v = value
    }

    func value() -> Int {
        return v
    }
}
Run Code Online (Sandbox Code Playgroud)

有一个Value对象数组存储在Any类型的变量中:

let any: Any = [Value(value: 1), Value(value: 2), Value(value: 3)]
Run Code Online (Sandbox Code Playgroud)

可以将Any转换为[Value]:

let arrayOfValue = any as? [Value] // [1, 2, 3]
Run Code Online (Sandbox Code Playgroud)

为什么不能将[任何]归咎于[有价值]?

let arrayOfValuable = any as! [Valuable] // compiler error BAD INSTRUCTION
let arrayOfValuable2 = any as? [Valuable] // nil
Run Code Online (Sandbox Code Playgroud)

Lop*_*Sae 6

更新:在Swift3中完全可以强制[Any]转换为[Valuable].只要阵列中的所有元素都可以投射,演员阵容就会成功; 否则演员会失败.

var strings: [Any] = ["cadena"]
var mixed: [Any] = ["cadena", 12]

strings as! [String] // ["cadena"]
mixed as? [String] // nil
mixed as! [String] // Error! Could not cast value...
Run Code Online (Sandbox Code Playgroud)

此前作为斯威夫特2:要制作[Valuable]出来的[Any],必须手动像函数来完成map其他的答案已经解释.

目前Swift中没有与泛型相关的协方差或逆变(从Swift 2开始).这意味着不同类型的数组(如[String][UIView])不能相互转换,也不能比较它们的类型.

[UIView]并且[UIButton]彼此之间没有层次结构,无论它UIButton是否为子类UIView.这就是为什么即使以下返回true:

Valuable.self is Any.Type // true
Run Code Online (Sandbox Code Playgroud)

由于同样的原因,以下转换产生错误:

var anyArray: [Any] = ["cadena"]

anyArray as! [String] // BAD_INSTRUCTION error
"some string" as! Double // BAD_INSTRUCTION error
Run Code Online (Sandbox Code Playgroud)

这两个分支没有任何关系,并且演员阵容是不可能的,因为这as!是一个强制演员,它会引发错误.


Ber*_*liv 2

这个对我有用:

let arrayOfValuable = arrayOfValue?.map { $0 as Valuable }
Run Code Online (Sandbox Code Playgroud)

或相同:

let arrayOfValuable2 = (any as? [Value])?.map { $0 as Valuable }
Run Code Online (Sandbox Code Playgroud)

总之,arrayOfValuable应该具有以下类型[Valuable]?

编辑:

或者试试这个:

let arrayOfAny: [Any] = [Value(value: 1), Value(value: 2), Value(value: 3)]
let arrayOfValuable3 = arrayOfAny.map { $0 as Valuable }
Run Code Online (Sandbox Code Playgroud)

当然,更好的方法是声明arrayOfAny[Valuable],这样以后就不会出现问题了。