导读大纲
- 1.0.1 在变量中捕捉 when 表达式
- 1.0.2 对任意对象使用 when 表达式
- 1.0.3 使用不带参数的 when 表达式
- when 表达式专题系列
- 从枚举类引出 when 表达式
1.0.1 在变量中捕捉 when 表达式
-
在前面的示例中,when 表达式的评估值是color变量
- 它是通过调用 measureColor() 函数获得的
-
为了避免无关变量(如本例中的color)干扰周围的代码
- <1> when 表达式也可以将其评估项捕获到一个变量中
- 在这种情况下,捕获变量的作用域仅限于 when 表达式的主体
- 同时还能在 when 表达式的分支中访问捕获变量(color)
- <1> when 表达式也可以将其评估项捕获到一个变量中
fun getWarmthFromSensor(): String {
return when(val color = measureColor()) { // <1>
Color.RED, Color.ORANGE, Color.YELLOW -> "warm (red = ${color.r})"
Color.GREEN -> "neutral (green = ${color.g})"
Color.BLUE, Color.INDIGO, Color.VIOLET -> "cold (blue = ${color.b})"
}
}
- 需要注意的是,当作为表达式使用时(即其结果用于赋值或作为返回值)
- 编译器会强制构造必须穷尽,意味着所有可能的路径都必须返回一个值
- 在前面的示例中,我们涵盖所有的枚举常量
- 从而使 when 结构变得详尽无遗
- 相反,我们也可以使用 else 关键字提供默认情况
- 如果编译器无法推断是否涵盖所有可能的路径
- 就会迫使我们提供默认情况
1.0.2 对任意对象使用 when 表达式
-
Kotlin 中的 when 结构实际上比其他语言中的 when 结构更加灵活
- 可以使用任何类型的对象作为分支条件
-
如果两种颜色可以在这个小调色板中混合,就将它们混合起来
- 我们的选项并不多,而且可以很容易地枚举出所有选项
- 如果颜色 c1 和 c2 分别是红色和黄色(反之亦然)
- 混合后的结果就是橙色,以此类推
- 要实现这一点,需要使用集合比较,Kotlin 标准库包含一个函数 setOf
- 该函数创建一个集合, 其中包含作为参数指定的对象
- <1> when 表达式的参数可以是任何对象
- 它会被检查是否与分支条件相等
- <2> 枚举可以混合的颜色对
- <3> 如果其他分支都不匹配, 则执行该分支
fun mix(c1: Color, c2: Color) =
when (setOf(c1, c2)) { // <1>
setOf(RED, YELLOW) -> ORANGE // <2>
setOf(YELLOW, BLUE) -> GREEN
setOf(BLUE, VIOLET) -> INDIGO
else -> throw Exception("Dirty color") // <3>
}
fun main() {
println(mix(BLUE, RED))
// GREEN
}
-
集合是一个元素的顺序并不重要的collection
- 如果两个集合包含相同的元素,它们就是相等的
- 因此,如果集合 setOf(c1, c2) 和 setOf(RED, YELLOW) 相等
- 那么 c1 是红色, c2 是黄色, 反之亦然
-
when 表达式依次将其参数与所有分支匹配,直到满足某个分支条件为止
- 因此,首先检查 setOf(c1,c2) 与 setOf(红色,黄色)是否相等
- 然后再逐个检查其他颜色对是否相等
- 如果其他分支条件都不满足,则评估 else 分支
- 由于 Kotlin 编译器无法推断出我们已经涵盖所有可能的颜色集组合
- 而且 when 表达式的结果会被用作 mix 函数的返回值
- 因此我们不得不提供一个默认情况,以保证 when 表达式确实是穷尽的
- 因此,首先检查 setOf(c1,c2) 与 setOf(红色,黄色)是否相等
-
在很多情况下,将任何表达式用作分支条件都能让你写出简洁漂亮的代码
- 在本例中,条件是相等检查
- 接下来,你将看到条件可以是任何布尔表达式
1.0.3 使用不带参数的 when 表达式
-
您可能已经注意到,上个示例的效率有点低
- 每次调用该函数,它都会创建多个 Set 实例
- 这些实例仅用于检查两种给定颜色是否与另两种颜色匹配
- 通常情况下, 这并不是一个问题
- 但如果经常调用该函数,值得以另一种方式重写代码
- 以避免创建许多需要由垃圾回收器清理的短期对象
- 每次调用该函数,它都会创建多个 Set 实例
-
为此,可以使用不带参数的 when 表达式
- 代码的可读性较差,但这往往是为获得更好性能而必须付出的代价
- <1> when表达式没有参数
- <2> 作为表达式使用时, “when” 的分支必须穷尽
fun mixOptimized(c1: Color, c2: Color) =
when { // <1>
(c1 == RED && c2 == YELLOW) || (c1 == YELLOW && c2 == RED) -> ORANGE
(c1 == YELLOW && c2 == BLUE) || (c1 == BLUE && c2 == YELLOW) -> GREEN
(c1 == BLUE && c2 == VIOLET) || (c1 == VIOLET && c2 == BLUE) -> INDIGO
else -> throw Exception("Dirty color") // <2>
}
fun main() {
println(mixOptimized(BLUE, YELLOW))
// GREEN
}
- 如果没有为 when 表达式提供参数,分支条件就是任何布尔表达式
- mixOptimized 函数的功能与 mix 之前的功能相同
- mixOptimized的优点是不会创建任何额外对象,但代价可读性较差