Dichiariamo in swift una funzione che prende come parametro una stringa e una closure:
1 2 3 4 |
func printWithPrefix(text: String, getPrefix: () -> String ) { let prefix = getPrefix() println(prefix + text) } |
Come si vede la closure (getPrefix) è usata internamente per ottenere il prefisso da inserire prima della stampa della stringa.
Per chiamare questa funzione usiamo il seguente codice:
1 2 |
let text = "Ciao" printWithPrefix(text, {() -> String in return "PRE"}) |
Nella closure la dichiarazione dei parametri e del tipo di ritorno possono essere automaticamente desunte dal prototipo di printWithPrefix, quindi possiamo ometterle e ottenere lo stesso risultato usando:
1 |
printWithPrefix(text, {return "PRE"}) |
Inoltre se la closure consiste di una sola espressione (come nel nostro caso) il risultato della espressione viene automaticamente usato come valore di ritorno, quindi riduciamo ancora:
1 |
printWithPrefix(text, {"PRE"}) |
Notiamo che la printWithPrefix si presta anche ad essere usata in casi più complessi in cui il prefisso è calcolato dinamicamente (in questo esempio notiamo anche la variabile text “catturata” dallo scope superiore):
1 2 3 4 5 6 7 8 |
printWithPrefix(text, { if text.isEmpty { return "" } else { return "NAME: " } } ) |
Ma torniamo all’esempio più semplice:
1 |
printWithPrefix(text, {"PRE"}) |
Qui entra in scena l’ @auto_closure. Questo attributo, inserito nella dichiarazione di un parametro closure di una funzione, ci permette di chiamare la funzione stessa omettendo le graffe intorno al codice stesso, cioè la funzione:
1 2 3 4 |
func printWithPrefix2(text: String, getPrefix: @autoclosure () -> String ) { let prefix = getPrefix() println(prefix + text) } |
può essere chiamata nel seguente modo:
1 |
printWithPrefix2(text, "PRE") // eliminate le {} |
In pratica è stato eseguito un auto-closure: l’attributo @auto_closure aggiunto davanti al tipo della closure nella dichiarazione ha indicato al sistema di aggiungere implicitamente le graffe ({}) intorno a quel parametro quando la funzione viene chiamata.
L’@auto_closure è valido solo per closure che non prevedono parametri passati ( () -> [TipoRitorno] ).
Inoltre se un parametro è dichiarato @auto_closure non può essere chiamato aggiungendo le graffe in modo esplicito:
1 |
printWithPrefix2(text, {"PRE"}) // errore di compilazione |
Se voglio inserire closure complesse in parametri auto_closure quindi, non potendo inserire esplicitamente le graffe, posso dichiarare una closure separata e poi passarla alla funzione, come in:
1 2 3 4 5 6 7 8 |
let myClosure = {() -> String in if text.isEmpty { return "" } else { return "NAME: " } } printWithPrefix2(text, myClosure()) |
Il codice di esempio lo trovate su github: Autoclosure.playground.