理解Scala枚举

123

我必须说我不理解Scala枚举类。 我可以复制粘贴文档中的示例,但我不知道发生了什么。

object WeekDay extends Enumeration {
  type WeekDay = Value
  val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value
}
import WeekDay._
  • 什么意思是type WeekDay = Value,我为什么要写那个?
  • val Mon = Value是什么意思?那到底是什么?
  • 为什么我需要导入WeekDay对象?
  • 当我写val day = WeekDay.Mon时,为什么它的类型是WeekDay.Value而不是WeekDay

2
我写了一个关于Scala枚举和替代方案的小概述,你可能会觉得它很有用:pedrorijo.com/blog/scala-enums/ - pedrorijo91
密封特质提供了一种极好的替代方案 - https://dev59.com/h2gu5IYBdhLWcg3wnYPo - Joey Baruch
1个回答

153

Enumeration 特质有一个类型成员 Value,代表枚举中的单个元素(实际上是一个内部类,但这里的差异无关紧要)。

因此,object WeekDay 继承了该类型成员。行 type WeekDay = Value 只是一个类型别名。它非常有用,因为当您在其他地方使用 import WeekDay._ 导入后,就可以使用该类型,例如:

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

相对而言,一个最小化的版本将会是:

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

你不必导入WeekDay对象的内容,但是您需要使用类型WeekDay.Value和限定个别成员。因此,示例将变为

def isWorkingDay(d: WeekDay.Value) = ! (d == WeekDay.Sat || d == WeekDay.Sun)
第二个问题是关于 val Mon, ... = Value 的含义。如果不了解 Enumeration 的实现,这确实非常令人困惑。这不是类型的赋值!它实际上是调用了同名的受保护方法Value,该方法返回一个具体的 Value 类型的实例。
Scala中你可以写成 val a, b, c = foo,对于每个值 abc,方法 foo 都将被反复调用。 Enumeration 利用这个技巧来增加内部计数器,以便使每个值都是唯一的。
如果打开 Scala API 文档中的 Enumeration 并单击 Visibility: All,您将看到该方法的出现。

2
谢谢,这很令人困惑,但我认为是正确的。我将使用密封的 case 类,它似乎更容易理解。 - Karel Bílek
2
我个人也更喜欢封闭的 case classes。虽然有点啰嗦,但内部计数器不可变等方面就不会出现太多魔法般的操作了。在 Scala 2.10 中,有一些关于如何更好地使用宏来编写枚举(与 Java 不同,Scala 的枚举不是语言结构而只是一个库解决方案)的想法。 - 0__
@0__ 请问您为什么要使用密封类来替换Scala中的枚举?Scala的枚举有什么问题吗? - x1a0
如果枚举值本身有成员怎么办?例如,如何为每个星期定义开放时间,如 Mon(8,20),...,Sun(0,0)? - simou
1
@simou,那么你确实应该使用一个密封特质和实际的子类。虽然我很难称这种情况为“枚举”,但你最好写成Open(Mon, 8, 20),这样天数就会保持一个平坦的枚举。 - 0__
@ZhangXiao,这些内容很令人困惑,这也是我为什么首先提出这个问题的原因:) [对于我的冒昧,我道歉] - Karel Bílek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接