Swift - 将协议数组向上转换为超级协议数组导致错误

Swift - upcasting array of protocol to array of super protocol causes error

在 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]'"

这似乎违反直觉,我想知道为什么不允许这样做。

试试这个代码 - 刚刚检查过,工作正常

let array2: [SuperProtocol] = array1.map { [=10=] as 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。这是因为,对于协议,当前已知的类型决定了使用哪个默认实现。所以转换数组不起作用——我认为原因是数组转换改变其包含的 objects' 行为是出乎意料的。

解决方法

如您所见,这行不通:

let farm : [CowLocomotion] = [Cow(), Cow(), Cow()]
let mammalFarm : [MammalLocomotion] = farm // doesn't work

如果需要,您可以通过将数组映射到所需的协议来解决此限制:

let farm = [Cow(), Cow(), Cow()]

farm.forEach { print([=15=].legs()) } // prints 4, 4, 4

let mammalFarm = farm.map { [=15=] as MammalLocomotion }

mammalFarm.forEach { print([=15=].legs()) } // prints 2, 2, 2

有关协议如何继承的更多信息,请参阅今年 WWDC 的 Protocol-Oriented Swift session 中的编程 - transcript here