在文章Kotlin学习 - 选择控制if 和when中有一句话:如果 when 作为一个表达式使用,则必须有 else 分支,因为Kotlin编译器会强制检查默认选项 ,除非编译器能够检测出所有的可能情况都已经覆盖了。 那什么情况下编译器能检测出所有的情况呢?就是本文章标题的两个种情况,枚举和密封类。
enum class Color{
RED,GREEN,BLUE,YELLOW
}
这里使用《Kotlin实战》书中的例子,新建一个枚举类Color
,和Java一样可以给枚举类声明属性和方法。
enum class Color(val r: Int, val g: Int, val b: Int) {
RED(255, 0, 0), GREEN(0, 255, 0),
BLUE(0, 0, 255), YELLOW(255, 255, 0);
fun getRgb() = (r * 256 + g) * 256 + b
}
新建一个Color枚举类,属性有三个r
,g
,b
,使用主构造函数进行了声明,getRgb
是类中定义的方法。
fun getColorMeaning(color: Color) = when (color){
Color.RED -> "passion"
Color.GREEN -> "vitality"
Color.BLUE -> "unhappy"
Color.YELLOW -> "happy"
}
上面代码有啥特点呢?
else
分支,如果when
中分支条件都是枚举类型,不需要else
分支;调用代码:
fun main() {
println(getColorMeaning(Color.RED))
}
//结果
passion
定义个请求结果类型接口Result
,结果只有两种成功或者失败,定义如下:
interface Result
class Success(val msg: String) : Result
class Failure(val msg: String) : Result
再定义一个获取结果的方法:
fun getResultMsg(result: Result) = when(result) {
is Success -> result.msg
is Failure -> result.error.message
else -> throw IllegalArgumentException()
}
由于Kotlin编译器会强制检查默认选项,所以when
分支中必须有else
,因此就算只有两个结果,也必须写else
,在这个例子中默认值不能返回一个有意义的值,因此会抛出一个异常。
总是不得不添加一个默认分支很不方便,尤其是添加一个新的子类的时候,如果忘记在when
中添加分支,编译器也没有任何提示,就会走到默认分支,抛出异常。
Kotlin提供解决方案-sealed
类,在类前面加上该修饰符,对所有可能创建的子类进行限定,直接子类必须嵌套在父类中。(我看其他博客可以写在外面,这里为了好理解,放在了密封类中)
sealed class Result{
class Success(val msg: String) : Result()
class Failure(val error: Exception) : Result()
}
方法修改如下:
fun getResultMsg(result: Result) = when (result) {
is Result.Success -> result.msg
is Result.Failure -> result.error.message
}
此时去掉else
即可,但是分支必须包括密封类的全部子类,否则编译不通过。