I'm learning swift and I'm stuck on the crazy closure with parameters syntax. The following works as the "right way" to do it.
enum Brew: Int {
case lager
case barleyWine
case porter
}
let beer = { (kind: Brew) -> Void in
print( "\(kind), smooth!")
}
let gin = { () -> Void in
print("gin & juice")
}
func sip( on drink: () -> Void ) {
print("Sip...")
drink()
}
func sip( on drink: (Brew) -> Void ) {
print("Sip...")
drink(brew.porter)
}
sip( on: beer )
sip( on: gin )
This prints...
Sip...
porter, smooth!
Sip...
gin & juice
However, that doesn't make much sense to me. The way it is coded any time I call sip() with a beer it assumes its a porter. It seems like I should be able to specify the brew in the call to sip rather than in the sip definition. Something like this...
sip( on: beer( brew.porter )
That way the beer closure is parameterized when it is called. Isn't that more readable and useful? Why would it NOT be this way? Is there a syntax that accomplishes this?
Also, shouldn't there be a way to write one sip() method with variable parameters so that it can take beer OR gin? How?
Closures are confusing!
Also, shouldn't there be a way to write one sip() method with variable parameters so that it can take beer OR gin?
Right now, beer
and gin
are different types of closures ( beer
takes a parameter while gin
doesn't), which is why you need two overloads of sip
- one to handle each type. Imagine what would happen if there were a single sip
that could accept both of them. How would it know whether to pass a parameter or not?
On the other hand, if your ultimate goal is something like this:
sip(on: beer(brew.porter))
Then declaring a single sip
is possible.
Right now, doing beer(brew.porter)
will call the beer
closure. The beer
closure returns Void
, and Void
can't be passed into sip
, so that won't work. Your intuition might say "Why can't beer(brew.porter)
return another closure, that, when called with no parameters, drinks a beer with a porter brew?" And congrats, you have discovered currying .
You can change beer
to do exactly that:
let beer = { (kind: Brew) -> (() -> Void) in // a closure that returns a closure!
// return { () -> Void in print("\(kind), smooth!") }
return { print( "\(kind), smooth!") } // short-hand
}
And now you only need this sip
:
func sip( on drink: () -> Void ) {
print("Sip...")
drink()
}
In the real world though, you often can't change beer
(because it's someone else's code, or it doesn't make sense). In that case, you must change how you call sip
:
// "{}" indicates a closure! You are putting the closure call "beer(brew.porter)" inside another closure.
sip(on: { beer(brew.porter) })
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.