Подтвердить что ты не робот

Как использовать Swift @autoclosure

Я заметил, что при записи assert в Swift первое значение вводится как

@autoclosure() -> Bool

с перегруженным методом для возврата общего значения T, чтобы проверить существование через LogicValue protocol.

Однако строго придерживаясь вопроса. Кажется, хочет, чтобы @autoclosure возвращал Bool.

Написание фактического закрытия, которое не принимает никаких параметров и возвращает Bool, не работает, он хочет, чтобы я вызывал замыкание, чтобы оно скомпилировалось, например:

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

Однако просто передача работ Bool:

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

Так что происходит? Что такое @autoclosure?

Изменить: @auto_closure было переименовано @autoclosure

4b9b3361

Ответ 1

Рассмотрим функцию, которая принимает один аргумент, простое замыкание, которое не принимает аргумента:

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

Чтобы вызвать эту функцию, мы должны перейти в замыкание

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

Если мы опустим фигурные скобки, мы передаем в выражении и что ошибка:

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

@autoclosure создает автоматическое закрытие вокруг выражения. Поэтому, когда вызывающий оператор пишет выражение типа 2 > 1, он автоматически завершается в замыкание, становясь {2 > 1}, прежде чем он будет передан в f. Поэтому, если мы применим это к функции f:

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

f(pred: 2 > 1)
// It true

Таким образом, он работает только с выражением без необходимости заключать его в закрытие.

Ответ 2

Вот пример: my print override (это 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(), таким образом, завернут в закрытие и не оценивается. Если мы находимся в режиме Release, это никогда не будет оценено, потому что item() не будет вызываться. Таким образом, мы имеем версию print, которая не оценивает свои аргументы в режиме Release.

Ответ 3

Описание auto_closure из документов:

Вы можете применить атрибут auto_closure к типу функции, который имеет тип параметра() и возвращает тип выражения (см. Атрибуты типа). Функция автозакрытия фиксирует неявное закрытие над указанным выражением, вместо самого выражения. в следующем примере используется атрибут 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.")

В основном, это означает, что вы передаете логическое выражение как этот первый аргумент вместо закрытия и автоматически создаете для него закрытие. Вот почему вы можете передать false в метод, потому что это логическое выражение, но не может пройти закрытие.

Ответ 4

Это показывает полезный случай @autoclosure https://airspeedvelocity.net/2014/06/28/extending-the-swift-language-is-cool-but-be-careful/

Теперь условное выражение, переданное как первый параметр, пока оно не будет автоматически завернуто в выражение замыкания и может быть вызвано каждый раз вокруг цикла

func until<L: LogicValue>(pred: @auto_closure ()->L, block: ()->()) {
    while !pred() {
        block()
    }
}

// doSomething until condition becomes true
until(condition) {
    doSomething()
}

Ответ 5

Это просто способ избавиться от фигурных скобок в вызове замыкания, простой пример:

    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