How Swift autoclosure Delaying works?

时间:2017-08-13 13:54:15

标签: swift closures

As mentioned in the Documentation - Autoclosure Section:

An autoclosure lets you delay evaluation, because the code inside isn’t run until you call the closure. Delaying evaluation is useful for code that has side effects or is computationally expensive, because it lets you control when that code is evaluated.

I am unable to understand exactly what's the logic behind the delaying.

When I tried to compare between the standard closure and the autoclosure:

func getMyString() -> String {
    print("Reaching My String")
    return "My String"
}

func testStandardClousre(closure: () -> String, isValid: Bool) {
    print("Reaching Test")

    if isValid {
        _ = closure()
    }
}

// calling:
testStandardClousre(closure: { () -> String in
    return getMyString()
}, isValid: false)

Naturally, because closure wouldn't be executed, the output would be:

Reaching Test

without printing "Reaching My String", i.e without reaching getMyString().

If that's the exact case when the closure marked as @autoclosure (giving the same output):

func testAutoClosure(closure: @autoclosure () -> String, isValid: Bool) {
    print("Reaching Test")

    if isValid {
        _ = closure()
    }
}

// calling
testAutoClosure(closure: getMyString(), isValid: false)

So what's the meaning of delaying? i.e How delaying works?

1 个答案:

答案 0 :(得分:1)

您的代码段不能成为延迟的好例子。如果您想查找延迟的含义,则需要将{ceiling(quantile(rnorm(20), seq(0, 8, length.out=8))); rnorm(10)} 与非关闭进行比较。

非闭合的一个例子:

@autoclosure

有时,您可能需要传递复杂计算结果才能生成错误消息。

enum LogLevel: Int {
    case debug, warning, error
}

extension LogLevel: Comparable {
    static func < (lhs: LogLevel, rhs: LogLevel) -> Bool {
        return lhs.rawValue < rhs.rawValue
    }
}

var currentLogLevel: LogLevel = .error
func outputLogNonClosure(_ level: LogLevel, message: String) {
    if level >= currentLogLevel {
        print(message)
    }
}

outputLogNonClosure(.debug, message: "Debug message")
//output nothing, calling cost can be acceptable.

在上面的后面的代码中,您可能希望在不需要输出时不评估func getMyStringSuperHeavy() -> String { var result = "" do { print("Assume doing very complex calculation to get Debug message...") result = "Debug message" } return result } outputLogNonClosure(.debug, message: getMyStringSuperHeavy()) //->Assume doing very complex calculation to get Debug message...... //The result of `getMyStringSuperHeavy()` is not used, but `getMyStringSuperHeavy()` is called.

autoclosure的一个例子:

getMyStringSuperHeavy()

在上一段代码中,func outputLogAutoClosure(_ level: LogLevel, message: @autoclosure ()->String) { if level >= currentLogLevel { print(message()) } } outputLogAutoClosure(.debug, message: "Debug message") //output nothing, calling cost can be acceptable. outputLogAutoClosure(.debug, message: getMyStringSuperHeavy()) //output nothing, calling cost can be acceptable as well. 的评估是延迟 ed,直到实际使用该值。

通常,声明为getMyStringSuperHeavy()的参数的计算成本不能省略,但在某些情况下可能不需要该值,您可以将其更改为arg: AType,并使用arg: @autoclosure ()->AType当真正需要它的价值时。

arg()可用于其他一些情况,但在每种情况下@autoclosurearg: AType 进行比较。)