什么是Swift中的尾随闭包语法?

4

根据Swift的闭包文档所述:

Swift的闭包表达式具有干净、清晰的风格,优化可以在常见情况下鼓励简洁、无杂乱语法的写法。这些优化包括:

  • 从上下文中推断参数和返回值类型
  • 单表达式闭包的隐式返回
  • 简写参数名称
  • 尾随闭包语法

那么什么是Swift闭包的“尾随闭包语法”?


5
在谷歌上输入“swift trailing closure”,第一个结果是:https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID102。 - Luca D'Alberti
https://www.hackingwithswift.com/example-code/language/what-is-trailing-closure-syntax - Bobby
5个回答

9

尾随闭包是写在函数调用的括号后面,即使它仍然是函数的一个参数。当您使用尾随闭包语法时,不需要将闭包的参数标签作为函数调用的一部分进行编写。

func doSomething(number:Int, onSuccess closure:(Int)->Void) {

    closure(number * number * number)

}

doSomething(number: 100) { (numberCube) in

    print(numberCube) // prints  1000000

}

该函数调用中缺少onSuccess参数标签。虽然闭包已在函数参数列表中包含,但Swift会将其从参数块中移除以使代码更易读。


2
  1. 一个闭包表达式,它被写在支持它的函数调用的括号外面(并且在括号之后)

这只是为了写得更简洁、更易读而存在的语法糖。

给你一个使用案例:

你有一个需要另一个函数(或闭包)作为参数的函数,像这样:

func fooFunc(paramfunc: () -> Void) {
    paramfunc();
}

调用函数并将函数作为参数传递是很常见的。如果给它一个闭包,意味着你所传递的参数是一个匿名函数,它被写在一对大括号{}中,并在开头有类型签名(它是一个匿名函数)。

当调用需要函数作为参数的函数时,在括号后面写闭包或省略括号(如果它是唯一的参数)(在Swift 5.3中支持多个尾随闭包)就可以使用尾随闭包语法。

fooFunc { () -> Void in
    print("Bar");
}

fooFunc() { () -> Void in
    print("Bar");
}

函数名后面的括号甚至可以省略。


2
如果您需要将闭包表达式作为函数的最后一个参数传递,并且该闭包表达式很长,那么编写尾随闭包可能会很有用。尾随闭包在函数调用的括号之后编写,即使它仍然是函数的参数。当您使用尾随闭包语法时,不需要将闭包的参数标签作为函数调用的一部分编写。
 func funcWithATrailingClosure(closure: () -> Void) {
// function body goes here
 }

// Here's how you call this function without using a trailing closure:
funcWithATrailingClosure(closure: {
// closure's body goes here
})

// Here's how you call this function with a trailing closure instead:
funcWithATrailingClosure() {
// trailing closure's body goes here
}

() can also be omitted. someFunctionThatTakesAClosure { } - Leo Dabus

1
当函数的最后一个参数是像这样的闭包时:
class Object {
  func foo(bar: String, baz: (() -> Void)) { }
}

您可以像正常调用一样使用它:

let obj = Object()
obj.foo(bar: "", baz: { foo() })

或者像这样的尾随

obj.foo(bar: "") { foo() }

另外,如果存在多个类似这样的尾随闭包:

func foo(bar: String, baz: (() -> Void), pippo: ((IndexPath) -> Void)) { }

然后如果你尝试像这样调用它:

obj.foo(bar: "") { _ in

} pippo: { _ in

}

出现以下错误:

上下文类型的闭包参数列表需要1个参数,不能隐式忽略

为了避免这个错误,你需要这样调用:

obj.foo(bar: "") {

} pippo: { _ in
    
}

最后,如果你想使用像Int这样的另一种闭包类型

func foo(bar: String, baz: ((Int) -> Void), pippo: ((IndexPath) -> Void)) { }

然后像这样调用:

obj.foo(bar: "") { _ in //baz

} pippo: { _ in
    
}

0

尾随闭包

如果你需要将一个闭包表达式作为函数的最后一个参数传递给函数,并且闭包表达式很长,那么将其编写为尾随闭包可能会很有用。尾随闭包写在函数调用的括号之后,即使它仍然是函数的参数。当你使用尾随闭包语法时,不需要在函数调用中写出闭包的参数标签。

https://docs.swift.org/swift-book/LanguageGuide/Closures.html#//apple_ref/doc/uid/TP40014097-CH11-ID102

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // function body goes here
}

// Here's how you call this function without using a trailing closure:

someFunctionThatTakesAClosure(closure: {
    // closure's body goes here
})

// Here's how you call this function with a trailing closure instead:

someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}

如果在调用函数时,你的闭包表达式是作为函数或方法的唯一参数,并且你提供了一个尾随闭包,那么你在调用函数或方法的名称后面不需要再写一对括号()。这是 Swift 语言中的一个简化写法。
reversedNames = names.sorted { $0 > $1 }

1
() can also be omitted. someFunctionThatTakesAClosure { } - Leo Dabus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接