简体   繁体   中英

Swift closure with parameter syntax

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM