Kotlin 1.3.11破坏了null安全性吗?

时间:2019-01-06 19:31:46

标签: kotlin

fun handle() : String {
    null?.let { return "Ololo"}
}

val result = handle()
result.trim() // kotlin.TypeCastException: null cannot be cast to non-null type kotlin.CharSequence

有什么想法为什么空安全的Kotlin函数返回空?

3 个答案:

答案 0 :(得分:8)

这是由于在Kotlin 1.3中为标准功能letrunapplyalso引入了contracts而导致的错误。

此修复程序针对版本1.3.20。有关详细信息,请参见KT-28061

答案 1 :(得分:4)

Kotlin编译器似乎在null不执行的情况下添加了let返回。这可能是一个错误,因为它不应该编译,也不在Kotlin的早期版本中。

如果我们只是编译您的示例,则会得到以下信息:

@NotNull
public final String handle() {
    return null;
}

我认为这只是编译器优化,因为null?.let()将永远不会执行。

使用实际变量会产生:

@NotNull
public final String handle() {
    return someNullableVariable != null ? "Ololo" : null;
}

换句话说,如果let()的引用是null,则不会执行。但是,由于此函数需要返回某些内容,因此编译器只是告诉它返回null,因为它没有其他返回值。

由于该函数被标记为@NotNull,因此Kotlin将对引用该函数的所有内容执行空检查:

fun someOtherMethod() {
    handle().trim()
}

成为

public final void someOtherMethod() {
    String handle = handle();

    if (handle != null) {
        StringsKt__StringsKt.trim(handle).toString();
        return;
    }

    throw new Exception("null cannot be cast to non-null type kotlin.CharSequence");
}

有两种方法可以解决此问题。您可以将handle()的返回类型更改为String?

fun handle(): String? {
    someNullableVariable?.let { return "Ololo" }
}

或者,如果变量为null,则可以返回其他内容:

fun handle(): String {
    someNullableVariable?.let { return "Ololo" }
    return "someNullableVariable was null"
}

答案 2 :(得分:3)

这一定是个错误,因为:

  • 缺少返回语句(或更优:表达式),因为传递给let的lambda不会被调用
  • String作为返回类型的函数永远不要返回null

有趣的是,在Kotlin 1.2.x中,它甚至无法编译:

fun handle() : String {
    null?.let { return "Ololo"}
} 
  

错误:(6,0)具有块体('{...}')的函数中需要的'return'表达式

在Kotlin 1.3.11中可以。

无论如何:

let将不会被调用,因为安全呼叫运算符?的计算结果为null(在这种情况下)。