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

对于这段代码,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 

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

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

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

有一个公开的功能要求 ,增加这种逻辑,但是,这不是在Kotlin团队的近期路线图。

恕我直言,如果一些应用程序逻辑是相互排斥的。 我宁愿使用when {}来声明性地表达全部情况,而不是使用if(...) else if(..) else来组成逻辑。

使用when{}指定全部条件时,可以帮助开发人员只关注特定的情况,这对于调试和稍后的更改更加容易。

相反, 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!") 

你可以稍微重构你的if表达式,所以它会减少检查,并将smart-cast应用到r2

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