This compiles:
let s = SignalsService()
s.addListener( "key", callback: { a, b in print( "success" ) } )
This does not:
let s = SignalsService()
let cb = { a, b in print( "success" ) }
s.addListener( "key", callback: cb )
Throwing the error Ambiguous reference to member 'print'
at the let cb = ...
line.
Why is that then?
In
s.addListener( "key", callback: { a, b in print( "success" ) } )
the compiler can infer the type of the closure from the context,
i.e. from the type of the addListener()
method. If that method is
for example declared as
func addListener(key : String, callback: (Int, Int) -> Void)
then the compiler can infer that the argument
{ a, b in print( "success" )
is a closure taking two Int
parameters and returning Void
.
In
let cb = { a, b in print( "success" ) }
there is no such context, therefore the compiler cannot know
the type of the closure. The return type can be inferred as
Void
because the closure consists of a single expression,
but you have to specify the types of the parameters, e.g.
let cb = { (a : Int, b : Int) in print( "success" ) }
Expanding on @MartinR's excellent answer.
Swift needs to be able to infer that cb
is of type (Int, Int)->()
, or you could explicitly set the type:
let cb: (Int, Int)->() = { a, b in print( "success" ) }
Then you could notice that a
and b
are unused and replace them with _
:
let cb: (Int, Int)->() = { _ in print( "success" ) }
Why can we get away with a single _
when the function takes 2 parameters? In this case, Swift knows there are 2 parameters, so the _
takes the place of the tuple containing all of the parameters. It replaces (_, _)
.
You can use _
with @MartinR's answer:
let cb = { (_:Int, _:Int) in print( "success" ) }
or you can write it like:
let cb = { (_:(Int, Int)) in print( "success" ) }
which can be read as:
cb
takes two parameters of typeInt
which it ignores and prints "success"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With