Scala不像Java那样有类型安全的枚举。给定一组相关的常量,在Scala中如何最好地表示这些常量?


当前回答

从Scala 3开始,现在有一个enum关键字,它可以表示一组常量(和其他用例)

enum Color:
   case Red, Green, Blue

scala> val red = Color.Red
val red: Color = Red
scala> red.ordinal
val res0: Int = 0

其他回答

http://www.scala-lang.org/docu/files/api/scala/Enumeration.html

示例使用

  object Main extends App {

    object WeekDay extends Enumeration {
      type WeekDay = Value
      val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
    }
    import WeekDay._

    def isWorkingDay(d: WeekDay) = ! (d == Sat || d == Sun)

    WeekDay.values filter isWorkingDay foreach println
  }

你可以使用一个密封的抽象类来代替枚举,例如:

sealed abstract class Constraint(val name: String, val verifier: Int => Boolean)

case object NotTooBig extends Constraint("NotTooBig", (_ < 1000))
case object NonZero extends Constraint("NonZero", (_ != 0))
case class NotEquals(x: Int) extends Constraint("NotEquals " + x, (_ != x))

object Main {

  def eval(ctrs: Seq[Constraint])(x: Int): Boolean =
    (true /: ctrs){ case (accum, ctr) => accum && ctr.verifier(x) }

  def main(args: Array[String]) {
    val ctrs = NotTooBig :: NotEquals(5) :: Nil
    val evaluate = eval(ctrs) _

    println(evaluate(3000))
    println(evaluate(3))
    println(evaluate(5))
  }

}

从Scala 3开始,现在有一个enum关键字,它可以表示一组常量(和其他用例)

enum Color:
   case Red, Green, Blue

scala> val red = Color.Red
val red: Color = Red
scala> red.ordinal
val res0: Int = 0

我必须说,上面skaffman从Scala文档中复制的示例在实践中用处有限(您还可以使用case对象)。

为了获得最接近Java Enum的东西(即使用合理的toString和valueOf方法——也许你要将枚举值持久化到数据库中),你需要稍微修改它。如果你使用skaffman的代码:

WeekDay.valueOf("Sun") //returns None
WeekDay.Tue.toString   //returns Weekday(2)

鉴于使用以下声明:

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon = Value("Mon")
  val Tue = Value("Tue") 
  ... etc
}

你会得到更合理的结果:

WeekDay.valueOf("Sun") //returns Some(Sun)
WeekDay.Tue.toString   //returns Tue

声明命名枚举的一种稍微不那么冗长的方式:

object WeekDay extends Enumeration("Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat") {
  type WeekDay = Value
  val Sun, Mon, Tue, Wed, Thu, Fri, Sat = Value
}

WeekDay.valueOf("Wed") // returns Some(Wed)
WeekDay.Fri.toString   // returns Fri

当然,这里的问题是,您需要保持name和val的顺序同步,如果name和val声明在同一行上,这将更容易做到。