【问题标题】:Why does if not null not work for mutable variables?为什么 if not null 不适用于可变变量?
【发布时间】:2021-10-18 13:58:32
【问题描述】:

此代码无法编译。

class MyClass {
        var w: String? = "Hello"
        init {
            if(w!=null) {
                println(w.length)
            }
        }
    }

编译器错误:智能转换为“String”是不可能的,因为“w”是一个可变属性,此时本可以更改。 这是什么意思? 类似的代码编译完美。

fun main(args: Array<String>) {
    var w: String? = "Hello"
    if(w!=null) {
        println(w.length)
    }
}

它们是相似的,因为根据我的理解,在这两种情况下,变量w 都将被实例化,if 块将紧随其后运行。那么为什么这段代码可以完美编译呢?

【问题讨论】:

    标签: kotlin null


    【解决方案1】:

    一般来说,这些错误是因为编译器不能保证在空检查和假定它不为空的用法之间不能更改变量。在大多数情况下,这是因为另一个线程可以同时修改变量。

    例如,在另一个 init 块中可能有一些代码产生了一个可以更改变量值的线程:

    class MyClass {
        var w: String? = "Hello"
    
        init {
            thread {
                w = null
            }
        }
    
        init {
            if (w!=null) {
                println(w.length)
            }
        }
    }
    

    编译器不会检查所有可能产生类似影响的代码,因此它更倾向于保守并给你一个错误。

    main方法的情况下,变量是本地的,所以编译器可以更容易地保证它不能被其他任何东西改变。

    要解决此问题,您可以在访问 w 属性时创建一个中间局部变量:

    val myW = w
    if (myW != null) {
        println(myW.length)
    }
    

    或者使用let:

    w?.let { nonNullW ->
        println(nonNullW.length)
    }
    

    【讨论】:

      【解决方案2】:

      在您的第一个代码块中,w 是一个属性。在您的第二个代码块中,w 是一个局部变量。

      一个可变属性不能被智能转换,因为编译器不能确保属性的值在检查类型/可空性和使用值之间不会改变。

      当你需要使用一个可为空的属性时,为了避免做一个非空断言,你必须先将它复制到一个局部变量中。您可以显式执行此操作,也可以使用范围函数。

      //Explicit
      val localW = w
      if (localW != null) {
          println(localW.length)
      }
      
      // The common ?.let pattern
      w?.let { println(it.length) }
      
      // run with function reference
      w?.length?.run(::println)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-12-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多