Scala 枚举的惰性评估?

Lazy evaluation of Scala Enumerations?

考虑以下将所有数字按字母顺序排列从 1 到 9 的代码片段:

object AlphabetizedDigit extends Enumeration {
    type AlphabetizedDigit = Value
    val one, two, three, four, five, six, seven, eight, nine = Value
}

println(for(i <- Range(0, AlphabetizedDigit.maxId)) yield (i, AlphabetizedDigit(i)))

由于零索引,println 的输出会有点不直观:

jason@debian:~/code/atomicscala$ scala EnumIDRange.scala 
Vector((0,one), (1,two), (2,three), (3,four), (4,five), (5,six), (6,seven), (7,eight), (8,nine))

处理此问题的一种方法是更改​​ AlphabetizedDigit 成员的定义,如下所示:

val one = Value(1)
val two, three, four, five, six, seven, eight, nine = Value

然后确保 Range1 而不是 0 开始。然后输出是直观的:

jason@debian:~/code/atomicscala$ scala EnumIDRange.scala 
Vector((1,one), (2,two), (3,three), (4,four), (5,five), (6,six), (7,seven), (8,eight), (9,nine))

但是,如果您只是想切换枚举的起始索引,我不太喜欢将声明分成两行这一事实。因此,我尝试了以下,编译得很好:

val one, two, three, four, five, six, seven, eight, nine = Value(1)

但是,在运行时,由于使用了重复的 ID,我抛出了 AssertionError。这对我来说很有意义,这是行不通的,但我很好奇为什么这个错误是在运行时而不是编译时抛出的。

如果您查看 the source code for Scala's Enumeration,您将看到以下内容:

/** The cache listing all values of this enumeration. */
@transient private var vset: ValueSet = null
@transient @volatile private var vsetDefined = false

和:

/** The values of this enumeration as a set.
 */
def values: ValueSet = {
  if (!vsetDefined) {
    vset = (ValueSet.newBuilder ++= vmap.values).result()
    vsetDefined = true
  }
  vset
}

所以似乎直到需要时才实际评估值集,因此错误仅在运行时出现。这看起来确实是实现 Enumeration 的糟糕方式,但我通常更喜欢使用密封特征和大小写 类 和对象,所以无论如何很少处理 Enumerations *耸耸肩*。

关于0的索引问题,为什么不添加一个zero条目呢?

val zero, one, two, three, four, five, six, seven, eight, nine = Value

如果你愿意,你仍然可以从 1 数起:

scala> println(for(i <- Range(1, AlphabetizedDigit.maxId)) yield (i, AlphabetizedDigit(i)))
Vector((1,one), (2,two), (3,three), (4,four), (5,five), (6,six), (7,seven), (8,eight), (9,nine))

或者从 0 开始计数并得到所有十位数字:

println(for(i <- Range(0, AlphabetizedDigit.maxId)) yield (i, AlphabetizedDigit(i)))
Vector((0,zero), (1,one), (2,two), (3,three), (4,four), (5,five), (6,six), (7,seven), (8,eight), (9,nine))

可以使用Enumeration的第二个构造函数,例如:

object AlphabetizedDigit extends Enumeration(1) {
    type AlphabetizedDigit = Value
    val one, two, three, four, five, six, seven, eight, nine = Value
}

表单文档:new Enumeration(initial: Int).