代码之家  ›  专栏  ›  技术社区  ›  Nickolay Savchenko

Kotlin 1.3.11是否破坏了零安全?

  •  6
  • Nickolay Savchenko  · 技术社区  · 6 年前
    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 回复  |  直到 6 年前
        1
  •  8
  •   Ilya    6 年前

    这是由于引入 contracts 对于标准功能 let , run , apply , also 在Kotlin 1.3。

    修复的目标是1.3.20版。见 KT-28061 详情。

        2
  •  4
  •   TheWanderer    6 年前

    看起来Kotlin编译器正在添加 null 万一退还 let 不执行。这可能是一个bug,因为它不应该编译,在以前的Kotlin版本中也不应该编译。

    如果我们只是编译您的示例,我们得到:

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

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

    使用实际变量得出:

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

    换言之, let() 如果其引用为 无效的 . 但是,由于这个函数需要返回一些东西,编译器只是告诉它返回 无效的 因为没有其他东西可以返回。

    因为函数被标记 @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" }
    }
    

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

    fun handle(): String {
        someNullableVariable?.let { return "Ololo" }
        return "someNullableVariable was null"
    }
    
        3
  •  3
  •   Willi Mentzel user670265    6 年前

    它必须是一个bug,因为:

    • 由于lambda传递给 let 不会被调用
    • 函数与 String 作为返回类型不应返回 null .

    有趣的是,在Kotlin1.2.x中,这甚至不能编译:

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

    错误:(6,0)具有块体(“…”)的函数中需要“return”表达式

    在Kotlin 1.3.11中是这样的。

    在任何情况下:

    不会被调用,因为安全呼叫操作员 ? 评估为 无效的 (在这种情况下)。