如何使用Swift @autoclosure

我注意到在Swift中编写一个assert时,第一个值被input为

 @autoclosure() -> Bool 

用重载方法返回一个通用的T值,通过LogicValue protocol来testing是否存在。

但是严格地坚持这个问题。 它似乎想要一个@autoclosure返回一个Bool

编写一个不带参数的实际闭包,返回一个Bool不起作用,它需要我调用闭包来编译它,如下所示:

 assert({() -> Bool in return false}(), "No user has been set", file: __FILE__, line: __LINE__) 

不过简单地通过布尔工程:

 assert(false, "No user has been set", file: __FILE__, line: __LINE__) 

那么发生了什么? 什么是@autoclosure

编辑: @auto_closure被重命名为@autoclosure

考虑一个只带一个参数的函数,一个不带参数的简单的闭包:

 func f(pred: () -> Bool) { if pred() { print("It's true") } } 

要调用这个函数,我们必须传入一个闭包

 f(pred: {2 > 1}) // "It's true" 

如果我们省略大括号,我们传递一个expression式,这是一个错误:

 f(pred: 2 > 1) // error: '>' produces 'Bool', not the expected contextual result type '() -> Bool' 

@autoclosure围绕expression式创build一个自动闭包。 所以当调用者写入一个像2 > 1这样的expression式时,它会在传递给f之前被自动封装到一个闭包中变成{2 > 1} 。 所以如果我们把这个应用到函数f

 func f(pred: @autoclosure () -> Bool) { if pred() { print("It's true") } } f(pred: 2 > 1) // It's true 

所以它只需要一个expression式,而不需要把它封装在一个闭包中。

这是一个实际的例子 – 我的print覆盖(这是Swift 3):

 func print(_ item: @autoclosure () -> Any, separator: String = " ", terminator: String = "\n") { #if DEBUG Swift.print(item(), separator:separator, terminator: terminator) #endif } 

当你说print(myExpensiveFunction()) ,我的print覆盖忽略了Swift的print并被调用。 myExpensiveFunction()因此被包装在一个闭包中, 而不是评估 。 如果我们处于发布模式,它将永远不会被评估,因为item()不会被调用。 因此,我们有一个print版本,在发布模式下不会评估它的参数。

文档中auto_closure的描述:

您可以将auto_closure属性应用于具有参数types为()并返回expression式types的函数types(请参见types属性)。 autoclosure函数捕获指定expression式的隐式闭包,而不是expression式本身。 以下示例在定义一个非常简单的断言函数时使用了auto_closure属性:

这里是苹果使用它的例子。

 func simpleAssert(condition: @auto_closure () -> Bool, message: String) { if !condition() { println(message) } } let testNumber = 5 simpleAssert(testNumber % 2 == 0, "testNumber isn't an even number.") 

基本上这意味着你传递一个布尔expression式作为第一个参数而不是一个闭包,它会自动为你创build一个闭包。 这就是为什么你可以传入false的方法,因为它是一个布尔expression式,但不能传递闭包。

这显示了@autoclosure一个有用的@autoclosure https://airspeedvelocity.net/2014/06/28/extending-the-swift-language-is-cool-but-be-careful/

现在,作为第一个parameter passing给until的条件expression式将被自动包装成一个闭包expression式,并且可以每次在循环周围调用

 func until<L: LogicValue>(pred: @auto_closure ()->L, block: ()->()) { while !pred() { block() } } // doSomething until condition becomes true until(condition) { doSomething() } 

这只是一个简单的例子,在closures调用中摆脱大括号的方法:

  let nonAutoClosure = { (arg1: () -> Bool) -> Void in } let non = nonAutoClosure( { 2 > 1} ) let autoClosure = { (arg1: @autoclosure () -> Bool) -> Void in } var auto = autoClosure( 2 > 1 ) // notice curly braces omitted