2015-11-13 139 views
0

考虑下面的代码片断,它按字母顺序排列所有的数字从1至9:Scala枚举的懒惰评估?

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的输出将是一个比特的未直观:

[email protected]:~/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。然后,输出的是直观的一个:

[email protected]:~/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。对我来说这很不合理,但我很好奇为什么在运行时抛出这个错误,而不是编译时。

+0

因为scala目前不是一种依赖类型的语言,它不能理解您将相同的ID提供给不同的值? – Odomontois

回答

3

如果你看一下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 * shrug *。

至于从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)) 
+0

谢谢,在Enumeration的值的评估中似乎确实存在某种懒惰,并且初始化'vset'的if条件确实如此。至于你对“AlphabetizedDigit”成员的适当索引问题,我完全同意把一个'零'成员放在一个明显的解决方案:这是一个更简单的例子,我正在摆弄一个更大的代码。 – Jason

5

可以使用枚举的第二个构造,例如:

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

form doc:new Enumeration(initial: Int)

+0

啊,这以更加优雅的方式解决了激励问题,我真的应该通过文档找到自己的东西。然而,在这个过程中,我学到了一些关于“Enumeration”如何工作的东西,所以这也很好。谢谢。 – Jason