我有一个案例,我想向服务注册一个参数或不注册参数闭包。总是有一个可用的参数,但为简洁起见,我希望能够不注册任何 arg 闭包,然后在这种情况下只调度没有可用参数的闭包。来自强大的 OO 和动态类型背景,我们喜欢多态调度和类继承树并让类型自己弄清楚,我可以将以下内容放在一起:
class AbstractAction<T> {
func publish(value:T) {
fatalError("you should override this")
}
}
class NullaryAction<T>: AbstractAction<T> {
var closure:() -> ()
override func publish(_:T) {
closure()
}
init(closure:()->()) {
self.closure = closure
}
}
class UnaryAction<T>: AbstractAction<T> {
var closure:(T) -> ()
override func publish(value:T) {
closure(value)
}
init(closure:(T)->()) {
self.closure = closure
}
}
var action:AbstractAction = UnaryAction<Int>(closure: { print("\($0)") })
action.publish(42)
action = NullaryAction<Int>(closure: { print("something happened") } )
action.publish(42)
所以我在我的控制台中42
看到了。something happened
伟大的。
但我想探索用struct
and/or来做这件事enum
。价值语义风靡一时。我认为这种enum
方法相对简单:
enum Action<T> {
case Nullary( ()->() )
case Unary( (T)->() )
func publish(value:T) {
switch self {
case .Nullary(let closure):
closure()
case .Unary(let closure):
closure(value)
}
}
}
var action = Action.Unary({ (arg:Int) -> () in print("\(arg)") })
action.publish(42)
action = Action<Int>.Unary( { print("shorthand too \($0)") } )
action.publish(42)
action = Action<Int>.Nullary({ print("something happened") })
action.publish(42)
做一个struct
方法,我的理解是我应该使用协议来捕获publish(value:T)
. 但这就是事情变得混乱的地方,因为协议显然不能与泛型混合?我试过了:
struct NullaryAction<T> {
typealias ValueType = T
var closure:() -> ()
}
struct UnaryAction<T> {
typealias ValueType = T
var closure:(T) -> ()
}
protocol Action {
typealias ValueType
func publish(value:ValueType)
}
extension NullaryAction: Action {
func publish(_:ValueType) {
self.closure()
}
}
extension UnaryAction: Action {
func publish(value:ValueType) {
self.closure(value)
}
}
var action:Action = UnaryAction(closure: { (arg:Int) -> () in print("\(arg)") })
action.publish(42)
action = UnaryAction<Int>(closure: { print("shorthand too \($0)") } )
action.publish(42)
action = NullaryAction<Int>(closure:{ print("something happened") })
action.publish(42)
这只会在底部产生很多错误。我曾尝试将扩展作为泛型(例如extension NullaryAction<T>:Action
),但它告诉我这T
是未使用的,即使我已将typealias
表达式放在扩展中。
是否可以使用结构/协议来做到这一点?我对枚举解决方案感到满意,但很失望我无法通过结构/协议方法实现它。