Swift 枚举涉及依赖协议的多个通用类型
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)'
}
}
我不明白为什么上面会给我一个错误。
奇怪的是,删除两个枚举通用约束中的任何一个,让枚举只剩下一个约束,就解决了这个问题...
请注意,协议 B 扩展了协议 A。与通用约束一起使用时不支持吗?
更新
将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
。为什么会失败?
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
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)'
}
}
我不明白为什么上面会给我一个错误。 奇怪的是,删除两个枚举通用约束中的任何一个,让枚举只剩下一个约束,就解决了这个问题...
请注意,协议 B 扩展了协议 A。与通用约束一起使用时不支持吗?
更新
将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
。为什么会失败?
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