斯威夫特 - 协议上溯造型阵列超级协议的阵列导致错误 [英] Swift - upcasting array of protocol to array of super protocol causes error

查看:133
本文介绍了斯威夫特 - 协议上溯造型阵列超级协议的阵列导致错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在斯威夫特,我注意到,我可以上溯造型符合一个所谓的协议对象,比方说子协议另一个名为 SuperProtocol 子协议。但我不能做同样的协议的数组。这里的例子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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆