基于结构/协议的Swift多态闭包调度

基于结构/协议的Swift多态闭包调度,swift,swift2,swift-protocols,swift-structs,Swift,Swift2,Swift Protocols,Swift Structs,我有一个例子,我想在服务中注册一个参数或无参数闭包。始终有一个可用的参数,但为了简洁起见,我希望能够注册没有arg闭包,然后在这种情况下只调度闭包而不使用可用的参数。来自强大的OO和动态类型背景,我们喜欢多态分派和类继承树,并让类型自行确定,我可以将以下内容结合在一起: class AbstractAction<T> { func publish(value:T) { fatalError("you should override this") } }

我有一个例子,我想在服务中注册一个参数或无参数闭包。始终有一个可用的参数,但为了简洁起见,我希望能够注册没有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)
要使用
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)
struct NullaryAction{
类型别名ValueType=T
var闭包:()->()
}
结构一元作用{
类型别名ValueType=T
var闭包:(T)->()
}
协议行动{
类型别名值类型
func发布(值:ValueType)
}
扩展空操作:操作{
func publish(uquo:ValueType){
self.closure()
}
}
扩展UnaryAction:Action{
func发布(值:ValueType){
自我封闭(价值)
}
}
var-action:action=UnaryAction(闭包:{(arg:Int)->()打印(“\(arg)”)})
行动.出版(42)
action=UnaryAction(闭包:{print(“速记也\($0)”)})
行动.出版(42)
action=NullaryAction(闭包:{print(“发生了什么”)})
行动.出版(42)
这只会在底部产生很多错误。我曾尝试将扩展作为泛型(例如,
extensionnullaryaction:Action
),但它告诉我,
T
未使用,即使我在扩展中放置了
typealias
表达式


是否可以使用结构/协议执行此操作?我对enum解决方案很满意,但很失望我无法用结构/协议方法实现它。

从您想要将结构强制转换到它们的协议这一事实判断(通过使用
var action:action=UnaryAction{…}
),我假设您不需要
publish
方法在调用它时拥有正确的签名

换句话说,通过使用
typealias
声明
Action
协议,编译器期望为结构的每个实例专门使用
publish
方法

这意味着您有两个选择:

  • 移除类型转换:
  • 例如:

    var action /*removed the :Action type casting */ = UnaryAction<Int>(closure: { (arg:Int) -> () in print("\(arg)") })
    action.publish(42)
    action = UnaryAction<Int>(closure: { print("shorthand too \($0)") } )
    action.publish(42)
    var anotherAction = NullaryAction<Int>(closure:{ print("something happened") }) //need to use another variable for this last one
    anotherAction.publish(42)
    

    此解决方案允许您继续进行类型转换,但您的
    publish
    方法都将具有相同的签名(
    .publish(value:Any)
    )。您还需要在执行闭包时说明这一点。

    协议和泛型在Swift中可能非常棘手。也许这个帖子中的答案可以帮助你:(另请参见forums.developer.apple.com/thread/7350)。然而,这两者都与某个协议函数的通用返回类型有关,但也许您可以使用动态类型魔术来解决一些问题:)我很想知道结果,例如您的特定示例(尝试修复某些问题,但失败得相当惨……)
    var action /*removed the :Action type casting */ = UnaryAction<Int>(closure: { (arg:Int) -> () in print("\(arg)") })
    action.publish(42)
    action = UnaryAction<Int>(closure: { print("shorthand too \($0)") } )
    action.publish(42)
    var anotherAction = NullaryAction<Int>(closure:{ print("something happened") }) //need to use another variable for this last one
    anotherAction.publish(42)
    
    protocol Action {
        func publish(value:Any)
    }
    
    struct NullaryAction<T>: Action {
        let closure: () -> ()
        init(closure: () -> ()) {
            self.closure = closure
        }
        func publish(value:Any) {
            self.closure()
        }
    }
    
    struct UnaryAction<T>: Action {
        let closure: (T) -> ()
        init(closure: (T) -> ()) {
            self.closure = closure
        }
        func publish(value:Any) {
            self.closure(value as! T) //Need to type cast here
        }
    }
    
    var action: Action = UnaryAction<Int>(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)