I can't understand why this one works:
var arr = [4,5,6,7]
arr.map() {
x in
return x + 2
}
while this one not
arr.map() {
x in
var y = x + 2
return y
}
with error
Playground execution failed: MyPlayground.playground:13:5: error: cannot invoke 'map' with an argument list of type '((_) -> _)' arr.map() {
The problem here is there error message. In general, when you see something like cannot invoke .. with ...
it means that the compiler's type inference has just not worked.
In this case, you've run up against one of the limitations of inference within closures. Swift can infer the type of single-statement closures only, not multiple-statement ones. In your first example:
arr.map() {
x in
return x + 2
}
There's actually only one statement: return x + 2
. However, in the second:
arr.map() {
x in
var y = x + 2
return y
}
There's an assignment statement (var y = x + 2
), and then the return. So the error is a little misleading: it doesn't mean you "can't invoke map() with this type of argument", what it means to say is "I can't figure out what type x or y is".
By the way, in single-statement closures, there are two other things that can be inferred. The return statement:
arr.map() {
x in
x + 2
}
And the variable name itself:
arr.map() { $0 + 2 }
It all produces the same compiled code, though. So it's really a matter of taste which one you choose. (For instance, while I think the inferred return
looks clean and easier to read, I don't like the $0
, so I generally always put x in
or something, even for very short closures. It's up to you, though, obviously.)
One final thing: since this is all really just syntax stuff, it's worth noting that the ()
isn't needed either:
arr.map { x in x + 2 }
As @MartinR pointed out, the compiler can infer some types from outer context as well:
let b: [Int] = arr.map { x in
var y = x + 2
return y
}
Which is worth bearing in mind. (it seems that the "one-statement" rule only applies when there's no other type info available)
Swift can't infer type every time. Even though it should see that y = x + 2
means y
is an Int
too. My guess is that Swift parses the closure in a certain order that makes it not aware of the return type ahead of time in your case.
This works:
arr.map() {
x -> Int in
var y = x + 2
return y
}
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