[英]Swift enum multiple generic types involving depending protocols
protocol ProtocolA {
func someFunc() -> Any
}
protocol ProtocolB: ProtocolA {
var someVar: Any { get }
}
enum MyEnum<T: ProtocolA, U: ProtocolB> {
case A(T)
case B(U)
}
protocol DataObject {
...
}
extension DataObject where Self: ProtocolB {
func doSomething() {
let x = MyEnum.B(self)
/// Compiler error:
/// Cannot invoke 'B' with an argument list of type '(Self)'
}
}
我不明白為什么上面給我一個錯誤。 奇怪的是,刪除兩個枚舉通用約束中的任何一個,使枚舉只有一個約束,解決了問題......
請注意,ProtocolB擴展了ProtocolA。 與通用約束一起使用時,是否不支持此功能?
UPDATE
將MyEnum
更改MyEnum
可以解決問題:
enum MyEnum {
typealias T = ProtocolA
typealias U = ProtocolB
case A(T)
case B(U)
}
但是,我仍然不明白為什么......
這個錯誤有點誤導。 讓我們簡化問題來探索它。
protocol ProtocolA {}
protocol ProtocolB: ProtocolA {}
enum MyEnum<T: ProtocolA, U: ProtocolB> {
case A(T)
case B(U)
}
struct AThing: ProtocolA {}
struct BThing: ProtocolB {}
let bThing = BThing()
let thing = MyEnum.B(bThing) // error: cannot invoke 'B' with an argument list of type '(BThing)'
所以現在我們DataObject
了同樣的問題而不需要DataObject
。 為什么這會失敗?
MyEnum
是通用的。 這意味着為了創建具體類型,它必須知道T
和U
的類型。 您提供了對這些類型的約束(一個符合ProtocolA
,另一個符合ProtocolB
),但您沒有具體說明它們是什么類型。
當我們到達這一行時:
let thing = MyEnum.B(bThing)
什么類型的thing
? 通過類型推斷,我們可以弄清楚U
是什么,但是什么是T
?
let thing: MyEnum<?, BThing> = MyEnum.B(bThing)
這里沒有足夠的上下文來解決它,所以我們必須明確地告訴編譯器:
let thing = MyEnum<AThing, BThing>.B(bThing)
所以完整類型的thing
是MyEnum<AThing, BThing>
,這是一種與MyEnum<OtherAThing, BThing>
不同的類型。 (正如[Int]
與[String]
類型不同,這就是為什么let xs = []
在沒有顯式類型定義的情況下不會編譯。)
你的第二個例子不通用,所以沒有問題。 它簡化為:
enum MyEnum {
case A(ProtocolA)
case B(ProtocolB)
}
綁定類型只是重命名類型,它們不會創建新類型(如未綁定的類型,或者Swift 2.2調用它, associatedtype
)。 所以我們知道A
接受任何ProtocolA
和B
接受任何ProtocolB
,並且所有MyEnum
實例具有相同的類型。
錯誤是不幸的,因為編譯器很困惑。 如果將此簡化為最基本的情況,則會得到更明確的錯誤。 這失敗的原因與您的示例完全相同。
enum MyEnum<T> {
case A
}
let x = MyEnum.A // error: generic parameter 'T' could not be inferred
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.