![](/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.