特定于枚举成员的通用约束
Generic constraints specific to an enum member
我有一个关联类型的协议:
protocol MyProtocol {
associatedtype Q
}
现在我想要一个像
这样的枚举
enum MyEnum<Q> {
case zero
case one(MyProtocol)
case two(MyProtocol, MyProtocol)
}
其中每个关联值都有 Q
作为其关联类型。这不起作用:
enum MyEnum<Q> {
case zero
case one<P: MyProtocol where P.Q == Q>(P)
case two<P1: MyProtocol, P2: MyProtocol where P1.Q == Q, P2.Q == Q>(P1, P2)
}
显然,单个枚举成员不能有自己的通用约束。
我唯一能想到的就是将这些约束移动到枚举声明中,但这会固定关联类型。为了证明为什么这不是我想要的,这是我希望能够做的:
struct StructA: MyProtocol {
typealias Q = Int
}
struct StructB: MyProtocol {
typealias Q = Int
}
var enumValue = MyEnum.one(StructA())
enumValue = .two(StructB(), StructA())
enumValue = .two(StructA(), StructB())
有没有解决这个限制的方法?
类型擦除。答案总是类型擦除。
您需要的是 AnyProtocol 类型:
struct AnyProtocol<Element>: MyProtocol {
typealias Q = Element
// and the rest of the type-erasure forwarding, based on actual protocol
}
现在您可以创建一个使用它们的枚举
enum MyEnum<Q> {
case zero
case one(AnyProtocol<Q>)
case two(AnyProtocol<Q>, AnyProtocol<Q>)
}
有关如何构建类型橡皮擦的更深入讨论,请参阅 A Little Respect for AnySequence。
Swift 不能将 PAT(具有关联类型的协议)讨论为真实类型甚至抽象类型。它们只能是约束。为了将它用作抽象类型,你必须将它提炼成类型橡皮擦。幸运的是,这是非常机械的,在大多数情况下并不困难。它是如此机械化,最终编译器有望为您完成这项工作。但是总得有人来组装盒子,今天就是你了。
我有一个关联类型的协议:
protocol MyProtocol {
associatedtype Q
}
现在我想要一个像
这样的枚举enum MyEnum<Q> {
case zero
case one(MyProtocol)
case two(MyProtocol, MyProtocol)
}
其中每个关联值都有 Q
作为其关联类型。这不起作用:
enum MyEnum<Q> {
case zero
case one<P: MyProtocol where P.Q == Q>(P)
case two<P1: MyProtocol, P2: MyProtocol where P1.Q == Q, P2.Q == Q>(P1, P2)
}
显然,单个枚举成员不能有自己的通用约束。
我唯一能想到的就是将这些约束移动到枚举声明中,但这会固定关联类型。为了证明为什么这不是我想要的,这是我希望能够做的:
struct StructA: MyProtocol {
typealias Q = Int
}
struct StructB: MyProtocol {
typealias Q = Int
}
var enumValue = MyEnum.one(StructA())
enumValue = .two(StructB(), StructA())
enumValue = .two(StructA(), StructB())
有没有解决这个限制的方法?
类型擦除。答案总是类型擦除。
您需要的是 AnyProtocol 类型:
struct AnyProtocol<Element>: MyProtocol {
typealias Q = Element
// and the rest of the type-erasure forwarding, based on actual protocol
}
现在您可以创建一个使用它们的枚举
enum MyEnum<Q> {
case zero
case one(AnyProtocol<Q>)
case two(AnyProtocol<Q>, AnyProtocol<Q>)
}
有关如何构建类型橡皮擦的更深入讨论,请参阅 A Little Respect for AnySequence。
Swift 不能将 PAT(具有关联类型的协议)讨论为真实类型甚至抽象类型。它们只能是约束。为了将它用作抽象类型,你必须将它提炼成类型橡皮擦。幸运的是,这是非常机械的,在大多数情况下并不困难。它是如此机械化,最终编译器有望为您完成这项工作。但是总得有人来组装盒子,今天就是你了。