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
然后确保 Range
从 1
而不是 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
的糟糕方式,但我通常更喜欢使用密封特征和大小写 类 和对象,所以无论如何很少处理 Enumeration
s *耸耸肩*。
关于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)
.
考虑以下将所有数字按字母顺序排列从 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
然后确保 Range
从 1
而不是 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
的糟糕方式,但我通常更喜欢使用密封特征和大小写 类 和对象,所以无论如何很少处理 Enumeration
s *耸耸肩*。
关于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)
.