在Swift中,我注意到我可以上载一个符合协议的对象,比方说SubProtocol
到另一个名为SuperProtocol
的协议,该协议是SubProtocol
的超级协议。但是我不能对协议数组做同样的事情。这是我在Playground中运行的示例代码:
protocol SuperProtocol {
}
protocol SubProtocol: SuperProtocol {
}
class MyObject: SubProtocol {
}
let value1: SubProtocol = MyObject()
let value2: SuperProtocol = value1 // No error here. Upcasting works.
let array1: [SubProtocol] = [MyObject()]
let array2: [SuperProtocol] = array1 // Error here "Cannot convert value of type '[SubProtocol]' to specified type '[SuperProtocol]'"
这似乎违反直觉,我想知道为什么不允许这样做。
最佳答案
原因与协议如何从类继承不同有关。
首先考虑协议可以具有默认实现,例如:
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()
他们的
legs()
方法响应我们所期望的:mammal.legs() // 2
cow.legs() // 4
但是现在让我们将
cow
强制转换为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-transcript here中,可以在Swift的面向协议编程中的会话中获得有关协议如何继承的更多信息。
关于arrays - Swift-将协议(protocol)数组上载到 super 协议(protocol)数组会导致错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36645974/