Kotlin2.3表示和处理选择:枚举和when
这一节讨论when的结构,它可以被认为是Java中switch结构的替代品,但是它更强大,也使用得更频繁。
2.3.1声明枚举类
- 声明一个简单的枚举类
enum class Color {
RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET
}
这是极少数Kotlin声明比Java更多关键字的例子,在Kotlin中用了enum和class两个关键字,而Java只用了enum一个关键字。Kotlin中,enum是一个所谓的软关键字:只有当它出现在class前面时才有特殊的意义,在其他地方可以把它当做普通的名称使用。与此不同的是,class仍然是一个关键字。
- 声明一个带属性的枚举类:
enum class Color(val r: Int, val g: Int, val b: Int) {
//在每个常量创建的时候指定属性值
RED(255, 0, 0), GREEN(0, 255, 0), BLUE(0, 0, 255);
//给枚举类定义一个方法
fun rgb() = (r * 256 + g) * 256 + b
}
>>> println(Color.BLUE.rgb())
255
这个例子展示了Kotlin语法中唯一必须使用分号的地方:如果要在枚举类中定义方法,就要使用分号把枚举常量列表和方法定义分开。
2.3.2使用when处理枚举类
假设需要一个函数来告诉你每种颜色对应的汉字,在Java中可以用switch语句完成,而Kotlin对应的是when。
与if相似,when是一个有返回值的表达式。因此可以写一个直接返回when表达式的表达式体函数:
fun getTranslate(color: Color) =
when (color) {
Color.RED -> "红"
Color.GREEN -> "绿"
Color.BLUE -> "蓝"
}
>>> println(getTranslate(Color.RED))
红
上面的代码根据传进来的color值找到对应的分支,并且不需要break语句。如果匹配成功,只有对应的分支会执行。也可以把多个值合并到同一分支,只需要用逗号隔开这些值:
fun getTranslate(color: Color) =
when (color) {
Color.RED, Color.BLUE -> "我喜欢的颜色"
Color.GREEN -> {
println("我不喜欢的颜色")
"绿"
}
}
2.3.3在when结构中使用任意对象
Kotlin中的when结构比Java中的switch强大得多,when允许任何对象来作为分支条件:
fun getTranslate(color: Color) =
when (color) {
setOf(Color.RED, Color.GREEN) -> "黄色"
Color.RED -> "红"
Color.GREEN -> "绿"
Color.BLUE -> "蓝"
else -> "不是三原色的色"
}
2.3.4使用不带参数的when
每次调用这个函数的时候,它都会创建一些set实例,作用却不是很大,一般来说问题不大,但是调用很频繁,它就值得用另一种方法重写,来避免创建额外的垃圾对象,但是代码可读性会变差。
fun mixColor(color1: Color, color2: Color) =
when {
(color1 == Color.RED && color2 == Color.GREEN) -> "黄"
(color1 == Color.YELLOW && color2 == Color.BLUE) -> "绿"
else -> "不知道啥色"
}
如果没有给when表达式提供参数,分支条件就是任意的布尔表达式。
2.3.5智能转换:合并类型检查和转换
要设置Toolbar菜单栏显示图标:
override fun onPrepareOptionsMenu(menu: Menu): Boolean {
if (menu is MenuBuilder){
//menu被智能转换了类型
menu.setOptionalIconsVisible(true)
}
return super.onPrepareOptionsMenu(menu)
}
在Kotlin中,要使用is检查来判断一个变量是否是某种类型。is检查和Java中的instanceOf相似。但是在Java中,如果已经检查过一个变量是某种类型并且要把它当做这种类型来访问其成员时,在instanceOf检查之后还要显式地加上类型转换。如果最初的变量会使用超过一次,常常选择把转换的结果存储在另一个单独的变量中。在Kotlin中,编译器完成了这些工作。如果检查过一个变量是某种类型,后面就不需要再转换它,可以直接当作检查过的类型使用。
当你对一个类的属性进行智能转换的时候,这个属性必须是一个val属性,而且不能自定义访问器,否则,每次对属性的访问是否都能返回同样的值将无从验证。
用as关键字来表示到特定类型的显式转换:
activity as MainActivity
2.3.6用when代替if
override fun onClick(v: View?) {
if (v?.id == R.id.button) {
println("111")
} else if (v?.id == R.id.button2) {
println("222")
} else if (v?.id == R.id.button3) {
println("333")
} else {
println("999")
}
}
可以改写为:
override fun onClick(v: View?) {
when {
v?.id == R.id.button -> println("111")
v?.id == R.id.button2 -> println("222")
v?.id == R.id.button3 -> println("333")
else -> println("999")
}
}
when表达式不仅限于检查值是否相等,还允许检查实参值的类型。