为什么我被迫使用!!在空检查的组合?

时间:2016-10-08 10:42:25

标签: kotlin

对于这段代码,Kotlin迫使我处理无效检查情况,而在另一条线上则没有,尽管情况相同:

if (r1 == null && r2 == null)
    throw IllegalArgumentException("All nulls!")
else if (r1 == null)
    return r2!!.reading // <----- I am forced to !! here
else if (r2 == null)
    return r1.reading // <----- The compiler does not complain in this line

这是一个错误还是一个功能?

3 个答案:

答案 0 :(得分:7)

Kotlin编译器没有以你期望的方式做出逻辑推断:“我已经检查过r1 == null和r2 == null,所以现在如果我只检查r1 == null,那么它必须认识到r2不为空“。它没有。你没有在那个分支中检查过r2,所以它没有看到它不是空的。

在第二种情况下,情况更简单:if (r1 == null) { ... } else { ... }。你在else内有另一张支票并不重要;编译器发现您在else检查的if (x == null)分支中,并且知道该值不为空。

有一个open feature request用于添加这种逻辑,但是,它不在Kotlin团队的近期路线图中。

答案 1 :(得分:2)

恕我直言,如果某些应用程序逻辑是互斥的。我更愿意使用when {}逐个声明地表达完整条件,而不是使用if(...) else if(..) else来组成逻辑。

使用when{}逐个指定完整条件可以帮助开发人员专注于特定情况,这样更容易进行调试和以后的更改。

相比之下,if else条件迫使开发人员从上到下进行跟踪以获得该部分逻辑的整体概念,这对其他人来说相对难以阅读并且难以指出无法访问的代码。

我遇到了一些复杂的if else代码,我必须构建一个真值表来理解整个逻辑部分。

回到这个问题。智能案例适用于when{}:)

实施1

val someReading = when {
    r1 != null && r2 == null -> r1.reading
    r1 == null && r2 != null -> r2.reading
    else -> throw IllegalArgumentException("All nulls!")
}

实施2

val someReading =
        r1?.reading
        ?: r2?.reading
        ?: throw IllegalArgumentException("All nulls!")

答案 2 :(得分:1)

您可以稍微重新构建if表达式,这样可以减少检查次数并将智能广播应用于r2

if (r1 == null) {
    if (r2 == null) throw IllegalArgumentException("All nulls!")
    return r2.reading
} else if (r2 == null) {
    return r1.reading
}