J'ai remarqué en écrivant un assert
in Swift que la première valeur est tapée comme
@autoclosure() -> Bool
avec une méthode surchargée pour renvoyer une valeur générique T
, pour tester l'existence via le LogicValue
protocol
.
Cependant, s'en tenir strictement à la question posée. Il semble vouloir un @autoclosure
qui retourne un Bool
.
Écrire une fermeture réelle qui ne prend aucun paramètre et retourne un Bool ne fonctionne pas, il veut que j'appelle la fermeture pour le compiler, comme suit:
assert({() -> Bool in return false}(), "No user has been set", file: __FILE__, line: __LINE__)
Cependant, passer simplement un Bool fonctionne:
assert(false, "No user has been set", file: __FILE__, line: __LINE__)
Alors, quoi de neuf? Quel est @autoclosure
?
Edit:@auto_closure
a été renommé @autoclosure
Prenons une fonction qui prend un argument, une fermeture simple qui ne prend aucun argument:
func f(pred: () -> Bool) {
if pred() {
print("It's true")
}
}
Pour appeler cette fonction, nous devons passer à une fermeture
f(pred: {2 > 1})
// "It's true"
Si nous omettons les accolades, nous passons une expression et c'est une erreur:
f(pred: 2 > 1)
// error: '>' produces 'Bool', not the expected contextual result type '() -> Bool'
@autoclosure
crée une fermeture automatique autour de l'expression. Ainsi, lorsque l'appelant écrit une expression telle que 2 > 1
, il est automatiquement intégré dans une fermeture pour devenir {2 > 1}
avant qu'il ne soit passé à f
. Donc, si nous appliquons ceci à la fonction f
:
func f(pred: @autoclosure () -> Bool) {
if pred() {
print("It's true")
}
}
f(pred: 2 > 1)
// It's true
Donc, cela fonctionne avec juste une expression sans avoir besoin de l'envelopper dans une fermeture.
Voici un exemple pratique - 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
}
Lorsque vous dites print(myExpensiveFunction())
, mon print
remplace celui de Swift print
et est appelé. myExpensiveFunction()
est donc enveloppé dans une fermeture et non évaluée. Si nous sommes en mode Release, cela sera jamais, car item()
ne sera pas appelé. Nous avons donc une version de print
qui n'évalue pas ses arguments en mode Release.
Description de auto_closure à partir de la documentation:
Vous pouvez appliquer l'attribut auto_closure à un type de fonction ayant le type de paramètre () et renvoyant le type d'une expression (voir Attributs de type). Une fonction autoclosure capture une fermeture implicite sur l'expression spécifiée, au lieu de l'expression elle-même. L'exemple suivant utilise l'attribut auto_closure pour définir une fonction d'assertion très simple:
Et voici l'exemple Apple utilise avec lui.
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.")
Fondamentalement, cela signifie que vous passez une expression booléenne en tant que premier argument au lieu d’une clôture et que cela crée automatiquement une fermeture pour vous. C'est pourquoi vous pouvez transmettre false dans la méthode car il s'agit d'une expression booléenne, mais vous ne pouvez pas transmettre de clôture.
Cela montre un cas utile de @autoclosure
https://airspeedvelocity.net/2014/06/28/extending-the-Swift-language-is-cool-but-be-careful/
Maintenant, l'expression conditionnelle passée en tant que premier paramètre à jusqu'à sera automatiquement intégrée dans une expression de fermeture et peut être appelée à chaque fois autour de la boucle.
func until<L: LogicValue>(pred: @auto_closure ()->L, block: ()->()) {
while !pred() {
block()
}
}
// doSomething until condition becomes true
until(condition) {
doSomething()
}
C'est juste un moyen de se débarrasser des accolades lors d'un appel de fermeture, exemple simple:
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