![](/img/trans.png)
[英]Swift - Downcasting an array of protocols to type crashes with unsafeBitCast Fatal Error
[英]Downcasting on protocols in Swift
我有以下代码:
protocol Step { /* body */ }
enum StepA: Int, CaseIterable, Step {
case one
case two
case three
}
enum StepB: Int, CaseIterable, Step {
case one
case two
case three
}
protocol Component {
var step: Step { get }
}
protocol ComponentA: Component {
var step: StepA { get }
}
protocol ComponentB: Component {
var step: StepB { get }
}
struct SomeComponentOfTypeA: ComponentA {
var step: StepA = StepA.one
}
let a = SomeComponentOfTypeA()
print(a.step)
a.step的类型我想成为StepA ,因为我正在以这种方式初始化。 但是,我不能这样做,因为:
struct SomeComponentOfTypeA: ComponentA {
var step: StepA = StepA.one
}
编译器告诉我:
类型“SomeComponentOfTypeA”不符合协议“组件”
基本上,它不知道因为我正在实现ComponentA ,所以我的步骤也应该是StepA类型。
作为一种解决方法,我发现如果我修改这部分:
protocol Component {
var step: Step { get }
}
进入:
protocol Component {
associatedtype SomeStep: Step
var step: SomeStep { get }
}
一切正常, a.step属于StepA ,完全没有问题......
问题:为什么这有效? 我基本上是通过使用关联类型SomeStep来隐藏Component的step属性是Step类型的事实。 这有点奇怪,不是吗? 我希望这可以正常工作而不必隐藏任何东西,为什么会发生这种情况? 它是如何工作的?
谢谢。 任何帮助将非常感激!
你真的需要所有的协议吗? 您可以使用关联值执行此操作:
protocol Step { /* body */ }
enum StepA: Int, CaseIterable, Step {
case one
case two
case three
}
enum StepB: Int, CaseIterable, Step {
case one
case two
case three
}
enum Component {
case typeA(StepA)
case typeB(StepB)
}
let component = Component.typeA(StepA.one)
错误在于协议的定义方式。
Step
类型的变量step
(一个协议)step
在协议 ComponentA 中重新声明SomeComponentOfTypeA
时,编译器会给出一个错误,因为它发现每个ComponentA
的StepA
类型的step
但不是每个Component
协议的Step
类型的 step。Component
中的step
变量可以是遵循协议Step
的任何类型 因此,如果您真的想在ComponentA
中为特定类型StepA
重新声明变量step
,那么您最终使用 generics 所做的就是这种情况的正确方法。
结构或枚举可以采用协议,因此它不会执行 class 多态性,因为它们不能被继承。 这也是为什么会有associatedtype
存在的原因之一。
回到您的问题,您在子协议中定义了一个与父协议同名的变量,但类型不同,这是允许的,因为协议不是具体类型。 但这不是类型重载,因为该协议的工作方式与 class 不同。
在这种情况下,您最好使用 generics,即associatedtype
类型。 但是如果非要使用这三个协议,只需要声明子协议即可。
...
protocol ComponentA: Component {}
protocol ComponentB: Component {}
struct SomeComponentOfTypeA: ComponentA {
var step: Step = StepA.one
}
struct SomeComponentOfTypeB: ComponentB {
var step: Step = StepB.two
}
let a = SomeComponentOfTypeA()
print(a.step)
print(type(of: a))
let b = SomeComponentOfTypeB()
print(b.step)
print(type(of: b))
Output:
one
SomeComponentOfTypeA
two
SomeComponentOfTypeB
另一种方法是满足您的需求。 限制SomeComponentOfTypeA
只允许StepA
类型。
protocol StepAProtocol { /* body */ }
protocol StepBProtocol { /* body */ }
enum StepA: Int, CaseIterable, StepAProtocol {
case one
case two
case three
}
enum StepB: Int, CaseIterable, StepBProtocol {
case one
case two
case three
}
protocol Component {
associatedtype T
var step: T { get }
}
protocol ComponentA: Component where T: StepAProtocol {}
protocol ComponentB: Component where T: StepBProtocol {}
struct SomeComponentOfTypeA: ComponentA {
var step: StepA = .one
}
struct SomeComponentOfTypeB: ComponentB {
var step: StepB = .two
}
struct SomeComponentOfTypeC: ComponentB {
var step: StepA = .two // error: Type 'StepA' does not conform to protocol 'StepBProtocol'
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.