简体   繁体   中英

Storing/passing Function Types from swift protocols

This bit of code crashes the swift (3, 3.1, 4) compiler:

protocol Test {
    func f()
}
let x = Test.f // crash

I would expect, perhaps naively, that the compiler would infer x as a Function Type with the signature (Test) -> (Void) -> Void , and that later on, I could call it like so:

let y = SomeClassConformingToTest()
x(y)()

I guess my question is: clearly the compiler should do something other than crash, but should Swift currently support this syntax?

As you say, the compiler should never crash; this is indeed a bug, and has been filed here . In it, Slava Pestov, a member of the Swift team, says:

We plan on making MyProtocol.someInstanceMethod work. You can already do this for classes, eg,

 class Foo { func f() { ... } } let f: Foo -> () -> () = Foo.f 

It should have the same behavior for protocols:

 protocol Foo { func f() } let f: Foo -> () -> () = Foo.f 

I plan on addressing this later.

And the bug report, as of the 8th of May 2017, is now marked as "In Progress", so hopefully this is something that will make it into the release build of Swift 4.0.

However, until implemented/fixed – a simple workaround is just to use a closure expression in order to act as a thunk for the partial application of the method with the instance to call it on:

protocol Test {
    func f()
}

struct S : Test {
    func f() {
        print("hello")
    }
}

let x: (Test) -> () -> Void = { $0.f }

let s = S()
x(s)() // "hello"

and of course, if you don't need the intermediate partially applied function, you can just say:

let x: (Test) -> Void = { $0.f() }

let s = S()
x(s) // "hello"

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