原因与协议与类的继承方式不同有关。
首先考虑协议可以有默认实现, 例如:
protocol MammalLocomotion {
func legs() -> Int
}
extension MammalLocomotion {
func legs () -> Int {
return 2
}
}
protocol CowLocomotion : MammalLocomotion {
}
extension CowLocomotion {
func legs () -> Int {
return 4
}
}
让我们创建符合这些协议的类:
class Mammal : MammalLocomotion {
}
class Cow : Mammal, CowLocomotion {
}
let mammal = Mammal()
let cow = Cow()
Their legs()
方法的响应符合我们的预期:
mammal.legs() // 2
cow.legs() // 4
但现在我们来投射cow
to Mammal
:
let cowAsMammal : Mammal = cow
cowAsMammal.legs() // 2
cow
原来有4条腿,但现在它有了2
。这是因为,对于协议,当前已知的类型决定了使用哪个默认实现。因此,转换数组不起作用 - 我认为原因是数组转换会意外地改变其所包含对象的行为。
解决方法
正如您所指出的,这是行不通的:
let farm : [CowLocomotion] = [Cow(), Cow(), Cow()]
let mammalFarm : [MammalLocomotion] = farm // doesn't work
如果需要,您可以通过将数组映射到所需的协议来解决此限制:
let farm = [Cow(), Cow(), Cow()]
farm.forEach { print($0.legs()) } // prints 4, 4, 4
let mammalFarm = farm.map { $0 as MammalLocomotion }
mammalFarm.forEach { print($0.legs()) } // prints 2, 2, 2
有关协议如何继承的更多信息,请参阅今年 WWDC 的面向协议的 Swift 编程会议 -文字记录在这里.