我发现,令人惊讶的是,如果未分配结果,Kotlin的when表达式不会强制处理所有可能的选项。
此示例编译:
import Options.*
fun main() {
print(Options.Great)
print(Options.Medium)
print(Options.TooLittle("needs more"))
}
fun print(opts: Options) {
when (opts) {
// Great -> println("It's great")
Medium -> println("It's so so...")
is TooLittle -> println("It's not enough because: ${opts.reason}")
}
}
sealed class Options {
object Great: Options()
object Medium: Options()
data class TooLittle(val reason: String): Options()
}
打印:
It's so so...
It's not enough because: needs more
注意它少了一个箱子。
我一直在将when
表达式的结果分配给一个未使用的变量,只是为了增强可理解性。。。
@Suppress("UNUSED_VARIABLE") val ignore = when(...) ...
如果注释掉的选项没有被取消注释,上面的例子就不会编译,就像我希望默认情况下那样。
有更好的方法来实现这一点吗?
mods注意:这不是关于在密封类中强制编译错误的问题的重复:我的问题特别是关于全面的when语句,它涉及密封类,就像在我的例子中一样,但也可以包括其他东西,比如枚举和具有有限大小写的类型,比如Boolean
。
关键是when
被强制覆盖所有可能的选项,当且仅当它是一个表达式而不是一个语句,也就是说,如果它处于以某种方式使用其结果值的位置。
一种解决方案是将结果分配给一个变量,但这会导致一个未使用的变量警告:
val coverAllOptions = when (opts) {
Great -> println("It's great")
Medium -> println("It's so so...")
is TooLittle -> println("It's not enough because: ${opts.reason}")
}
另一个可行但也会导致IDE警告的选项是在when
语句之后添加强制转换as Unit
。
我个人更喜欢的另一个解决方案是在when
的右大括号后面添加一些函数调用。它可能是一个无意义的调用,例如let
、apply
或run
,其中lambda为空,并且只包含一个记录目的的注释:
when (opts) {
Great -> println("It's great")
Medium -> println("It's so so...")
is TooLittle -> println("It's not enough because: ${opts.reason}")
}.run { /* cover all options */ }
正如@al3c在文章中所建议的那样,如果您经常需要,您可以创建一个扩展函数或一个扩展属性,它什么都不做,只用于将其附加到when
表达式:
val Any?.exhaustive get() = Unit
when (opts) {
Great -> println("It's great")
Medium -> println("It's so so...")
is TooLittle -> println("It's not enough because: ${opts.reason}")
}.exhaustive