Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

枚举

枚举是一组名称的集合。

Kotlin中的enum class是管理这些名称的便捷方式:

// Enumerations/Level.kt
package enumerations
import atomictest.eq

enum class Level {
  Overflow, High, Medium, Low, Empty
}

fun main() {
  Level.Medium eq "Medium"
}

创建一个枚举会生成enum名称的toString()方法。

main()中,您必须对枚举名称的每个引用进行限定,就像Level.Medium一样。您可以使用import将枚举中的所有名称引入到当前的命名空间(命名空间可以防止名称之间的冲突):

// Enumerations/EnumImport.kt
import atomictest.eq
import enumerations.Level.*   // [1]

fun main() {
  Overflow eq "Overflow"
  High eq "High"
}
  • [1] *导入了Level枚举内的所有名称,但不导入Level这个名称本身。

您可以将枚举值导入到定义枚举类的同一个文件中:

// Enumerations/RecursiveEnumImport.kt
package enumerations
import atomictest.eq
import enumerations.Size.*            // [1]

enum class Size {
  Tiny, Small, Medium, Large, Huge, Gigantic
}

fun main() {
  Gigantic eq "Gigantic"              // [2]
  Size.values().toList() eq           // [3]
    listOf(Tiny, Small, Medium,
      Large, Huge, Gigantic)
  Tiny.ordinal eq 0                   // [4]
  Huge.ordinal eq 4
}
  • [1] 我们在Size定义出现之前就导入了Size的值。
  • [2]import之后,我们不再需要限定访问枚举名称。
  • [3] 您可以使用values()遍历枚举名称。values()返回一个数组,因此我们调用toList()将其转换为列表。
  • [4] enum的第一个声明的常量具有ordinal值为零。每个后续的常量都会获得下一个整数值。

您可以使用when表达式对不同的枚举条目执行不同的操作。这里,我们导入了Level的名称以及其所有条目:

// Enumerations/CheckingOptions.kt
package checkingoptions
import atomictest.*
import enumerations.Level
import enumerations.Level.*

fun checkLevel(level: Level) {
  when (level) {
    Overflow -> trace(">>> Overflow!")
    Empty -> trace("Alert: Empty")
    else -> trace("Level $level OK")
  }
}

fun main() {
  checkLevel(Empty)
  checkLevel(Low)
  checkLevel(Overflow)
  trace eq """
    Alert: Empty
    Level Low OK
    >>> Overflow!
  """
}

checkLevel()仅针对两个常量执行特定的操作,而对于其他所有选项则表现正常(else情况)。

枚举是一种特殊类型的类,它有固定数量的实例,这些实例都列在类体内。除此之外,enum类的行为与常规类相同,因此您可以定义成员属性和函数。如果包含额外的元素,则必须在最后一个枚举值后添加一个分号:

// Enumerations/Direction.kt
package enumerations
import atomictest.eq
import enumerations.Direction.*

enum class Direction(val notation: String) {
  North("N"), South("S"),
  East("E"), West("W");  // 需要分号
  val opposite: Direction
    get() = when (this) {
      North -> South
      South -> North
      West -> East
      East -> West
    }
}

fun main() {
  North.notation eq "N"
  North.opposite eq South
  West.opposite.opposite eq West
  North.opposite.notation eq "S"
}

Direction类包含一个notation属性,每个实例都持有不同的值。您可以在括号中传递notation构造函数参数的值(例如North("N")),就像构造常规类的实例一样。

opposite属性的getter在访问时动态计算结果。

请注意,此示例中的when不需要else分支,因为所有可能的enum条目都已覆盖。

枚举可以使代码更具可读性,这总是值得提倡的。

Exercises and solutions can be found at www.AtomicKotlin.com.