如何使用Swift @autoclosure

Joe*_*her 143 closures swift

我注意到assert在Swift中编写第一个值时输入为

@autoclosure() -> Bool
Run Code Online (Sandbox Code Playgroud)

用重载方法返回一个通用T值,通过它来测试存在LogicValue protocol.

但严格坚持手头的问题.它似乎想要一个@autoclosure返回一个Bool.

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

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

然而,简单地通过Bool工作:

assert(false, "No user has been set", file: __FILE__, line: __LINE__)
Run Code Online (Sandbox Code Playgroud)

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

编辑: @auto_closure已重命名@autoclosure

edd*_*e_c 261

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

func f(pred: () -> Bool) {
    if pred() {
        print("It's true")
    }
}
Run Code Online (Sandbox Code Playgroud)

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

f(pred: {2 > 1})
// "It's true"
Run Code Online (Sandbox Code Playgroud)

如果我们省略大括号,我们传入一个表达式,这是一个错误:

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

@autoclosure在表达式周围创建一个自动闭包.因此,当调用者编写一个类似的表达式时2 > 1,它{2 > 1}会在传递给它之前自动包装到一个闭包中f.因此,如果我们将此应用于函数f:

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

f(pred: 2 > 1)
// It's true
Run Code Online (Sandbox Code Playgroud)

因此它只需要一个表达式,而无需将其包装在闭包中.

  • 很棒的解释.另请注意,在Swift 1.2中,'autoclosure'现在是参数声明的一个属性,所以它是`func f(@autoclosure pred :() - > Bool)` (5认同)
  • 有一篇关于他们这样做的博客文章https://developer.apple.com/swift/blog/?id=4 (3认同)
  • 实际上最后一个,不起作用.它应该是`f({2> 1}())` (2认同)

mat*_*att 29

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

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

当你说print(myExpensiveFunction()),我的print覆盖遮蔽了Swift的print并被称为.myExpensiveFunction()因此被包裹在封闭物中而不进行评估.如果我们处于发布模式,它将永远不会被评估,因为item()不会被调用.因此,我们的版本print不会在发布模式下评估其参数.


Con*_*nor 11

来自docs的auto_closure描述:

您可以将auto_closure属性应用于参数类型为()并返回表达式类型的函数类型(请参阅类型属性).autoclosure函数捕获指定表达式的隐式闭包,而不是表达式本身.以下示例在定义非常简单的断言函数时使用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.")
Run Code Online (Sandbox Code Playgroud)

基本上它意味着你传递一个布尔表达式作为第一个参数而不是一个闭包,它会自动为它创建一个闭包.这就是为什么你可以将false传递给方法,因为它是一个布尔表达式,但不能传递闭包.

  • 请注意,您实际上并不需要在此处使用`@ auto_closure`.代码在没有它的情况下工作正常:`func simpleAssert(condition:bool,message:String){if!condition {println(message)}}`.当你需要反复评估一个参数时使用`@ auto_closure`(例如,如果你正在实现一个`while`-like函数)或者你需要延迟一个参数的评估(例如,如果你正在实现短路`&&` ). (15认同)