斯威夫特 - 协议上溯造型阵列超级协议的阵列导致错误 [英] Swift - upcasting array of protocol to array of super protocol causes error
问题描述
在斯威夫特,我注意到,我可以上溯造型符合一个所谓的协议对象,比方说子协议
另一个名为 SuperProtocol 协议code>是
子协议
。但我不能做同样的协议的数组。这里的例子code,我在操场上跑步:
协议SuperProtocol {
}协议的子协议:SuperProtocol {
}类为MyObject:子协议{
}让值1:子协议=为MyObject()
这里SuperProtocol =值//没有错误:让VALUE2。上溯造型作品。让数组1:子协议] = [myObject的()]
让数组2:SuperProtocol] = ARRAY1 //这里的错误无法转换类型的值'[子协议]指定类型[SuperProtocol]'
这似乎违反直觉,我想知道为什么它不允许的。
的原因是协议如何从类继承不同的事情。
首先考虑的协议可以的默认实现的,例如:
协议MammalLocomotion {
FUNC腿() - > INT
}扩展MammalLocomotion {
FUNC腿() - > INT {
返回2
}
}协议CowLocomotion:MammalLocomotion {}扩展CowLocomotion {
FUNC腿() - > INT {
返回4
}
}
让我们符合这些协议类:
类哺乳动物:MammalLocomotion {}牛类:哺乳动物,CowLocomotion {}让哺乳动物=哺乳动物()
让牛=牛()
他们腿()
应对方法作为我们预期:
mammal.legs()// 2
cow.legs()// 4
但是,现在让我们来投牛
到哺乳动物
:
让cowAsMammal:哺乳动物=牛cowAsMammal.legs()// 2
牛
有4个腿,如今却 2
。这是因为,与协议,目前已知的类型确定哪一个默认实现。所以铸造阵列不工作 - 我认为的理由是,这将是出人意料的数组转换为改变其包含的对象的行为
解决方法
如您所知,这是不行的:
让农场:[CowLocomotion] = [牛(),牛(),牛()]
让mammalFarm:[MammalLocomotion] =农家//不起作用
如果你愿意,你可以在阵列映射到你想要的协议解决这个限制
让农场= [牛(),牛(),牛()]farm.forEach {打印($ 0.legs())} //打印纸4,4,4让mammalFarm = farm.map {$ 0作为MammalLocomotion}mammalFarm.forEach {打印($ 0.legs())} //输出2,2,2
这是协议如何继承更多信息,可以从今年的WWDC斯威夫特会议面向协议编程可用 - 这里成绩单的。
In Swift, I notice that I can upcast an object that conforms to a protocol called, let's say SubProtocol
to another protocol called SuperProtocol
which is a super protocol of SubProtocol
. But I can't do the same with an array of the protocol. Here's the example code that I ran in 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]'"
This seems counter-intuitive, and I'm wondering why it's not allowed.
The reason has to do with how protocols inherit differently from classes.
Consider first that protocols can have default implementations, for example:
protocol MammalLocomotion {
func legs() -> Int
}
extension MammalLocomotion {
func legs () -> Int {
return 2
}
}
protocol CowLocomotion : MammalLocomotion {
}
extension CowLocomotion {
func legs () -> Int {
return 4
}
}
Let's make classes that conform to these protocols:
class Mammal : MammalLocomotion {
}
class Cow : Mammal, CowLocomotion {
}
let mammal = Mammal()
let cow = Cow()
Their legs()
methods respond as we'd expect:
mammal.legs() // 2
cow.legs() // 4
But now let's cast cow
to Mammal
:
let cowAsMammal : Mammal = cow
cowAsMammal.legs() // 2
cow
had 4 legs, but now it has 2
. This is because, with protocols, the currently known type determines which default implementation is used. So casting the array doesn't work — I think the reasoning is that it would be unexpected for an array cast to alter its contained objects' behavior.
Workaround
As you've noted, this won't work:
let farm : [CowLocomotion] = [Cow(), Cow(), Cow()]
let mammalFarm : [MammalLocomotion] = farm // doesn't work
If you want, you can work around this limitation by mapping the array to the protocol you want:
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
More information on how protocols inherit is available in the Protocol-Oriented Programming in Swift session from this year's WWDC - transcript here.
这篇关于斯威夫特 - 协议上溯造型阵列超级协议的阵列导致错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!