Kotlin为什么在解析返回类型时表现不一致?

huangapple go评论57阅读模式
英文:

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 returns 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

huangapple
  • 本文由 发表于 2023年5月18日 07:01:57
  • 转载请务必保留本文链接:https://go.coder-hub.com/76276716.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定