Using Swift, I want to write a protocol that specifies that implementing classes must have a function that takes an enum (which adheres to a given protocol), where that enum type is specified generically. I've tried this:
使用Swift,我想编写一个协议,它指定实现类必须具有一个具有枚举(它遵循给定的协议)的函数,其中枚举类型是通用的。我已经试过这个:
protocol Message {}
protocol Subscriber {
func receive<T where T:Message>(message:T)
}
enum Greeting : Message {
case Hello, Goodbye
}
class SomeObject : Subscriber {
func receive<Greeting>(message: Greeting) {
switch message {
case .Hello:
println("Hello")
case .Goodbye:
println("Goodbye")
}
}
}
This fails to compile with the message "Enum case pattern cannot match values of the non-enum type 'Greeting'" at each of the case lines. This would appear to be because the Subscriber protocol expects something that is no more specialized than Message, but I set things up in terms of Greeting, which though it implements Message, is more specialized. (Am I right?)
这不能用“Enum case模式不能匹配非枚举类型的‘问候’的值”来进行编译。这似乎是因为订阅方协议期望的是不比消息更专门化的东西,但是我将事情设置为问候语,尽管它实现了消息,但它更专门化。(对吗?)
So, how do I do what I'm attempting to do, please?
那么,我该怎么做呢?
1 个解决方案
#1
9
The generic type parameter T
should still be generic in the implementation of Subscriber
. You can do what you ask using a typealias
in protocol Subscriber
and enforce the Message
superclass constraint on it:
泛型类型参数T在订阅服务器的实现中仍然应该是泛型的。您可以在协议订阅器中使用typealias,并对其强制执行消息超类约束:
protocol Message {}
protocol Subscriber {
typealias MessageType: Message
func receive (message: MessageType)
}
enum Greeting : Message {
case Hello, Goodbye
}
class SomeObject : Subscriber {
typealias MessageType = Greeting
func receive (message: MessageType) {
switch message {
case .Hello:
println("Hello")
case .Goodbye:
println("Goodbye")
}
}
}
Having a generic receive
prevents you from switching on the enum
fields:
有一个泛型接收可以防止您切换到enum字段:
protocol Message {}
protocol Subscriber {
func receive <T: Message> (message: T)
}
enum Greeting : Message {
case Hello, Goodbye
}
class SomeObject : Subscriber {
func receive <T: Message> (message: T) {
}
}
let obj = SomeObject()
obj.receive(Greeting.Hello)
#1
9
The generic type parameter T
should still be generic in the implementation of Subscriber
. You can do what you ask using a typealias
in protocol Subscriber
and enforce the Message
superclass constraint on it:
泛型类型参数T在订阅服务器的实现中仍然应该是泛型的。您可以在协议订阅器中使用typealias,并对其强制执行消息超类约束:
protocol Message {}
protocol Subscriber {
typealias MessageType: Message
func receive (message: MessageType)
}
enum Greeting : Message {
case Hello, Goodbye
}
class SomeObject : Subscriber {
typealias MessageType = Greeting
func receive (message: MessageType) {
switch message {
case .Hello:
println("Hello")
case .Goodbye:
println("Goodbye")
}
}
}
Having a generic receive
prevents you from switching on the enum
fields:
有一个泛型接收可以防止您切换到enum字段:
protocol Message {}
protocol Subscriber {
func receive <T: Message> (message: T)
}
enum Greeting : Message {
case Hello, Goodbye
}
class SomeObject : Subscriber {
func receive <T: Message> (message: T) {
}
}
let obj = SomeObject()
obj.receive(Greeting.Hello)