英文:
Why does Kotlin resolve return type inconsistently?
问题
The extra unreachable return statement after the while loop in value 3, 4, and 5 is required to satisfy the Kotlin compiler's return type inference. When you directly use value.or(::getValue)
or value.or(anonymousFunction)
, the compiler can infer the return type correctly from the function reference or the lambda expression.
However, in value 3, 4, and 5, when you use a lambda expression directly as an argument to .or
, the Kotlin compiler struggles to infer the return type accurately. Adding the extra return statement helps the compiler understand that the lambda indeed returns a String
in these cases. This is why the extra return statement is necessary for consistency in type inference.
In summary, the inconsistency arises because of how Kotlin's type inference works in different contexts. The extra return statement clarifies the return type when directly using inline anonymous functions and lambdas as arguments.
英文:
Given the following code:
inline fun <reified T> T?.or(other: () -> T): T {
return this ?: other()
}
fun getValue(): String {
while (true) {
return "Value 1"
}
}
fun main() {
val value: String? = null
// get value from getValue() function if value is null
val valueFromFunction = value.or(::getValue)
println(valueFromFunction)
// get value from anonymous function if value is null
val anonymousFunction: () -> String = fun(): String {
while (true) {
return "Value 2"
}
}
val valueFromAnonymous: String = value.or(anonymousFunction)
println(valueFromAnonymous)
// get value from lambda if value is null
val lambda: () -> String = lambda@ {
while (true) {
return@lambda "Value 3"
}
return@lambda ""
}
val valueFromLambda: String = value.or(lambda)
println(valueFromLambda)
// get value from inline anonymous function if value is null
val valueFromInlineAnonymous: String = value.or(fun(): String {
while (true) {
return "Value 4"
}
return ""
})
println(valueFromInlineAnonymous)
// get value from inline lambda if value is null
val valueFromInlineLambda: String = value.or {
while (true) {
return@or "Value 5"
}
return@or ""
}
println(valueFromInlineLambda)
}
Why is it needed for value 3, 4 and 5 to add the extra unreachable return statement after the while loop, whereas with value 1 and 2 I don't need to?
If I remove the unreachable return statement for inline anonymous functions and for lambdas, the code doesn't compile because it thinks that the return type is Unit
, however when a function reference is used or if the anonymous function is saved to a variable, this extra return statement is not needed. Also, for a lambda that is saved to a variable, the extra unreachable return statement is still needed.
Is there any good reason for this inconsistency?
答案1
得分: 1
Lambda cases are instances of this rather old bug [KT-24191] 或者 [KT-25023]。我怀疑匿名函数文字案例也与此有关。还有许多类似的问题,涉及到类型检查器无法理解无限循环内的 return
。这个[评论]解释了可能发生的情况:
而问题是关于这种情况:
fun foo() { val x = run<Int> { while (true) { return@run 1 // 错误:类型不匹配:推断类型为 Unit,但预期为 Int } } }
我们应该如何对这种构造进行类型检查?问题在于
while
的类型是Unit
(因为它是一个语句),但在 lambda(对于run
)中作为最后的表达式使用,应该是类型为Int
。
英文:
The lambda cases are instances of this rather old bug KT-24191, or KT-25023. I suspect the anonymous function literal case is also related. There are also many other similar issues about the typechecker not understanding return
s inside infinite loops.
This comment explains what is probably going on:
> And the question is about such case:
>
> fun foo() {
> val x = run<Int> {
> while (true) {
> return@run 1 // Error: Type mismatch: inferred type is Unit but Int was expected
> }
> }
> }
>
> How should we typecheck such constructs? Problem: the type of while
> is Unit
(because it's a statement), but it's used here as the last
> expression in lambda (for run
) and should be of the type Int
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论