Как использовать 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
?
Edit: @auto_closure
была переименована в @autoclosure
5 ответов
рассмотрим функцию, которая принимает один аргумент, простое закрытие, которое не принимает аргумента:
func f(pred: () -> Bool) {
if pred() {
print("It's true")
}
}
чтобы вызвать эту функцию, мы должны пройти в закрытие
f(pred: {2 > 1})
// "It's 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's true")
}
}
f(pred: 2 > 1)
// It's true
таким образом, он работает только с выражением без необходимости обернуть его в закрытие.
вот практический пример - мой 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 к типу функции, который имеет параметр type of (), который возвращает тип выражения (см. атрибут type.) Функция autoclosure фиксирует неявное закрытие над указанным выражением вместо самого выражения. Этот в следующем примере используется атрибут auto_closure при определении очень простая функция утверждать:
и вот пример, который apple использует вместе с ним.
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 в метод, потому что это логическое выражение, но не могу пройти закрытие.
Это показывает полезный случай @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()
}
Это просто способ избавиться от фигурных скобок в вызове закрытие, простой пример:
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