如何使用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