Can I use a name of the lambda as the parameter pa

2019-08-17 17:05发布

问题:

I can write a lambda expression outside of parenthesis, but I cannot put it there by name. I have tried many ways:

val plus3: (Int,Int,Int)->Int = {a,b,c->a+b+c}
println(apply3(1,2,3){a,b,c->a+b+c})  // OK
println(apply3(1,2,3){plus3}) // Type mismatch. Required: Int, Found: (Int,Int,Int)->Int
println(apply3(1,2,3){(plus3)}) // Type mismatch. Required: Int, Found: (Int,Int,Int)->Int
println(apply3(1,2,3)plus3)   // unresolved reference 
println(apply3(1,2,3){plus3()})   // value captured in a closure
println(apply3(1,2,3){(plus3)()})   // value captured in a closure

What is the syntax to put a name there (outside of parenthesis)?

I don't know why, but in the documentation there is not a word on the theme. It says we could put lambda there, but not a word about a variable or constant that denotes that lambda.

回答1:

I don't know why, but in the documentation there is not a word on the theme.

Yes, there is:

In Kotlin, there is a convention that if the last parameter to a function is a function, and you're passing a lambda expression as the corresponding argument, you can specify it outside of parentheses

plus3 is an identifier and not a lambda expression, so you can't specify it outside of parentheses.

The type of plus3 is (Int,Int,Int->Int). The same as of {a,b,c->a+b+c}. Look again at the messages that I am getting from Kotlin compiler.

You mean the error messages when you pass { plus3 }? By Kotlin rules { plus3 } is a lambda which ignores its argument (if any) and returns plus3. So the rule applies, and apply3(1,2,3){plus3} means the same as apply3(1,2,3,{plus3}).

It sees plus3 as Int.

Exactly the opposite: it expects to see an Int as the return value of the lambda and sees plus3 which is (Int,Int,Int) -> Int.

So, the problem here is not of the high philosophical nature, but seems pure syntactic.

That was exactly my point: the rule is purely syntactic, it's applied before the compiler knows anything about type or value of plus3, and so it doesn't know or care whether this value happens to be a lambda.

The rule could instead say

In Kotlin, there is a convention that if the last parameter to a function has a function type, you can specify it outside of parentheses

in which case apply3(1,2,3) plus3 would work. But it doesn't.



回答2:

Placing a lambda expression outside of a function call's parentheses is the same as placing it inside the parentheses like this:

println(apply3(1, 2, 3, { a, b, c -> a + b + c }))

From here, we can simply assign the lambda to a val (as you have done) which results in:

val plus3: (Int, Int, Int) -> Int = { a, b, c -> a + b + c }
println(apply3(1, 2, 3, plus3))