返回
Swift 5.3 新特性解析:多尾闭包,一个自相矛盾的特性
IOS
2023-10-08 20:48:52
多尾闭包:Swift 中备受争议的特性
精简与混乱:争议之根源
在 Swift 5.3 之前,使用带有单个尾闭包的函数时,可以省略尾闭包标签,并在圆括号之外直接书写尾闭包。这种语法简洁明了,提高了代码的可读性。
然而,当涉及多个尾闭包时,Swift 5.3 中的多尾闭包特性引起了争议。它允许将多个尾闭包传递给一个函数,同时省略尾闭包标签,如下所示:
func doSomething(withClosures: ((Int) -> Void, (String) -> Void)) {
// ...
}
// 新写法
doSomething { (number: Int), (text: String) in
// ...
}
虽然这种语法保持了精简性,但它也带来了混乱和歧义。由于缺少尾闭包标签,很难识别每个闭包的作用和传入的类型,这会导致代码难以阅读和维护。
自相矛盾的特性
多尾闭包特性的自相矛盾之处在于,它试图在精简性与清晰性之间取得平衡。虽然它确实简化了某些场景的代码,但它却以牺牲可读性和可维护性为代价。
当函数具有多个参数类型时,省略尾闭包标签会导致代码中出现歧义。例如,考虑以下函数:
func doSomething(withParameters: (Int, String)) {
// ...
}
使用多尾闭包语法时,这段代码可以这样编写:
doSomething { number, text in
// ...
}
在这种情况下,number
和 text
变量的类型不明确,这可能导致混乱和潜在的错误。
最佳实践
考虑到多尾闭包的争议性质,建议在使用时遵循以下最佳实践:
- 避免使用多尾闭包,特别是当函数具有多个参数类型时。
- 如果必须使用多尾闭包,请提供清晰的注释或文档来解释每个闭包的作用。
- 考虑使用命名闭包,它可以提供更好的可读性和可维护性。
命名闭包允许为每个闭包指定一个名称,使其在代码中更容易识别和理解。例如,上述代码可以用命名闭包重写如下:
func doSomething(withClosures: ((Int) -> Void, (String) -> Void)) {
// ...
}
// 使用命名闭包
doSomething {
(number: Int) in
// ...
}.{
(text: String) in
// ...
}
代码示例
// 精简语法
func doSomething(withClosure: (Int) -> Void) {
// ...
}
doSomething { number in
// ...
}
// 多尾闭包语法
func doSomething(withClosures: ((Int) -> Void, (String) -> Void)) {
// ...
}
doSomething { number, text in
// ...
}
// 命名闭包语法
func doSomething(withClosures: ((Int) -> Void, (String) -> Void)) {
// ...
}
doSomething {
(number: Int) in
// ...
}.{
(text: String) in
// ...
}
常见问题解答
-
为什么多尾闭包引起了争议?
争议源于多尾闭包语法带来的精简性和混乱之间的权衡。
-
什么时候应该使用多尾闭包?
建议避免使用多尾闭包,特别是当函数具有多个参数类型时。
-
如何解决多尾闭包带来的歧义问题?
使用命名闭包或提供清晰的注释或文档来解释每个闭包的作用。
-
多尾闭包与命名闭包有何区别?
命名闭包允许为每个闭包指定一个名称,从而提高可读性和可维护性。
-
为什么使用多尾闭包时建议遵循最佳实践?
最佳实践可以确保代码的可读性、可维护性,并避免潜在的错误。