I have function returning a lambda based on an input String
condition using if
statement, which works fine - using this modified example from Head First Kotlin:
fun getConversionLambda(str: String): (Double) -> Double {
if (str == "CelsiusToFahrenheit")
return { it * 1.8 + 32 }
if (str == "KgToPounds")
return { it * 2.204623 }
return { it }
}
But since that's an obvious good place to use when
instead, and I use the <function declaration> = <expression>
format, including the return type, then at compile or pre-compile time, I get an Unresolved reference: it
error:
fun getConversionLambda2(str: String): (Double) -> Double = when(str) {
"CelsiusToFahrenheit" -> { it * 1.8 + 32 }
"KgToPounds" -> { it * 2.204623 }
else -> { it }
}
Even if I specify it as the result of return
within the function block, or assign it to a variable first and then return, I still get the Unresolved reference
error:
fun getConversionLambda3(str: String): (Double) -> Double {
return when (str) {
"CelsiusToFahrenheit" -> { it * 1.8 + 32 }
"KgToPounds" -> { it * 2.204623 }
else -> { it }
}
}
Only way I could get it to work is by specifying the lambda's input variable-type in the lambda:
// and infers the `(Double) -> Double` return type correctly if removed
fun getConversionLambda4(str: String): (Double) -> Double = when(str) {
"CelsiusToFahrenheit" -> { x: Double -> x * 1.8 + 32 }
"KgToPounds" -> { x: Double -> x * 2.204623 }
else -> { x: Double -> x }
}
(my main
:)
fun main(args: Array<String>) {
println("getCL: ${getConversionLambda("KgToPounds")(2.5)}")
// println("getCL2: ${getConversionLambda2("KgToPounds")(2.5)}")
// println("getCL3: ${getConversionLambda3("KgToPounds")(2.5)}")
println("getCL4: ${getConversionLambda4("KgToPounds")(2.5)}")
}
Why does the if
version not have a problem with it
? It's obviously inferring the lambdas' parameter type and doing the one-param-it
based on getConversionLambda
's definition's explicit return type. So why not for the when
-version 2 & 3? I'm on Kotlin v1.4.32.
Edit: It seems any 'expression assignment' version of if
& when
prduces this issue unless I explicitly specify the parameter type for the lambda:
// Unresolved reference: it
fun getConversionLambda1A(str: String): (Double) -> Double =
if (str == "KgToPounds") { it * 2.204623 } else { it }
// Unresolved reference: it
fun getConversionLambda1B(str: String): (Double) -> Double {
return if (str == "KgToPounds") { it * 2.204623 } else { it }
}
But these two versions with the lambda parameter specified don't produce the error:
// works
fun getConversionLambda1Aokay(str: String) =
if (str == "KgToPounds") { x: Double -> x * 2.204623 } else { x: Double -> x }
// works
fun getConversionLambda1Bokay(str: String): (Double) -> Double {
return if (str == "KgToPounds") { x: Double -> x * 2.204623 } else { x: Double -> x }
}
The issue is that you're not within the scope of the passed in function when trying to reference "it". Just add braces and you're all set.
fun getConversionLambda1A(str: String): (Double) -> Double =
if (str == "KgToPounds") { { it * 2.204623 } } else { { it } }
fun getConversionLambda2(str: String): (Double) -> Double = when(str) {
"CelsiusToFahrenheit" -> {{ it * 1.8 + 32 }}
"KgToPounds" -> {{ it * 2.204623 }}
else -> {{ it }} }