如何在Swift中"生成"闭包类型别名?

Mic*_*ord 15 syntax closures ios swift

为了使我的代码更容易阅读,我在Swift中使用类型别名用于各种类型的闭包.我有以下基本的闭包:

public typealias FailureClosure = (error: NSError?) -> Void
public typealias ProgressClosure = (progress: Float32) -> Void
public typealias BasicClosure = () -> Void
Run Code Online (Sandbox Code Playgroud)

我想添加一个typealias支持通用数组的闭包,但我似乎无法弄清楚它的语法.这是我能够得到的,但我得到编译时错误" 使用未声明的类型'T' "

public typealias ArrayClosure = <T>(array:[T]?) -> Void
Run Code Online (Sandbox Code Playgroud)

有人知道怎么做这个吗?或者即使有可能吗?

Rob*_*ier 11

不,这目前不可行.如果它可能的,你所期望的语法为:

public typealias ArrayClosure<T> = (array:[T]?) -> Void
Run Code Online (Sandbox Code Playgroud)

然后你会喜欢它ArrayClosure<Int>.但它目前不合法.

也就是说,我不推荐这些类型的别名.它们模糊不清,而不是照亮它们.比较这个签名:

func foo(onError: FailureClosure)
Run Code Online (Sandbox Code Playgroud)

有:

func foo(onError: NSError? -> Void)
Run Code Online (Sandbox Code Playgroud)

要保存几个字符,可以强制调用者猜测FailureClosure传递的内容.该errorprogress标签不真正帮助你(你还需要使用progress in ...).

一个很有意义的案例就在附近progress,但我认为你想要的类型是:

public typealias Progress = Float32
Run Code Online (Sandbox Code Playgroud)

这里不要误解我,在创建新类型时输入别名会非常有用.Progress是一种碰巧实现为float的类型.但是你正在做的很多事情(绝对与ArrayClosure其他人一起使用,并且在较小程度上与其他人一起)只是在不创建新类型的情况下创建新语法,而这通常会让人感到困惑而不是有用.


要调用您的特定示例,以及为什么过度使用类型别名会导致您使设计过于复杂:

func foo(failure: ((error: NSError?) -> ())? = nil)
Run Code Online (Sandbox Code Playgroud)

你是对的,这真的很复杂.相比:

func foo(failure: NSError -> Void = {_ in return})
Run Code Online (Sandbox Code Playgroud)

这里有两大变化.没有理由有一个带有可选错误的故障块.总是传递错误(如果没有错误,为什么会failure被调用?).并且没有理由将故障块作为可选项.如果您确实需要默认值,只需使默认值不执行任何操作.两个选项消失了,所有消费和实现代码变得更简单.始终要仔细考虑是否绝对必须是可选的.可选项增加了很多复杂性; 不要轻易添加它们.

就个人而言,我可能会在很多情况下使用重载执行此操作:

func foo(#failure: NSError -> Void) { ...  }

func foo() {
  foo(failure:{ _ in return })
}
Run Code Online (Sandbox Code Playgroud)

我只是觉得理解发生的事情要容易一些.但无论哪种方式都没问题.


编辑(2014年12月):在写了几个月的Swift之后,我在下面的评论中更加喜欢@David的方法,即使用一个可选的闭包,但不是错误.特别是给定Swift的可选链接语法(failure?()),它通常会更清晰.

func foo(failure: (NSError -> Void)? = nil)
Run Code Online (Sandbox Code Playgroud)

  • 为了使失败块成为一个可选的对比意见,我认为它确实更好地保留了意图,使它成为可选的,而不是使其需要一个空的默认值.它明确告诉用户"如果需要,您可以获取(可选)错误信息." 它真的不会使你的代码复杂化,因为你可以使用可选的折叠,它只是作为`失败?(错误)`我同意明智地使用typealias并且没有理由让error参数是可选的,因为它的定义确实必须存在. (3认同)