gpt4 book ai didi

带有结构/协议(protocol)的 Swift 多态闭包分派(dispatch)

转载 作者:行者123 更新时间:2023-11-28 08:50:55 24 4
gpt4 key购买 nike

我有一个案例,我想在服务中注册一个参数或没有参数闭包。总是有可用的参数,但为了简洁起见,我希望也能够注册无参数闭包,然后在这种情况下只分派(dispatch)没有可用参数的闭包。来自强大的 OO 和动态类型背景,我们喜欢多态分派(dispatch)和类继承树并让类型自己弄清楚,我可以将以下内容放在一起:

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 做这件事和/或 enum .值(value)语义风靡一时。 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方法,我的理解是我应该使用协议(protocol)来捕获 publish(value:T) 的公共(public)接口(interface).但这就是事情变得困惑的地方,因为协议(protocol)显然不能与泛型混合?我试过:

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扩展中的表达式。

是否可以使用结构/协议(protocol)来做到这一点?我对枚举解决方案很满意,但很失望我无法用结构/协议(protocol)方法实现它。

最佳答案

根据您想要将结构转换为它们的协议(protocol)这一事实(通过使用 var action: Action = UnaryAction {...}),我假设您不需要publish 方法以在调用时获得正确的签名。

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

这意味着您有两个选择:

  1. 移除类型转换:

例子:

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 方法也具有与您的结构相同的签名。如果您的结构专门用于处理 Ints,那么您将拥有 .publish(value: Int)

  1. 使协议(protocol)非通用

示例:

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)

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

关于带有结构/协议(protocol)的 Swift 多态闭包分派(dispatch),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34211256/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com