我有一个枚举类来表示值的类型.该类的代码非常简单:
object Type extends Enumeration {
type Type = Value
val tInt, tBoolean, tString, tColor, tFont, tHAlign, tVAlign, tTextStyle, tUnknown = Value;
def fromValue (value:Any) : Type.Type = {
value match {
case a:Int => tInt
case a:Boolean => tBoolean
case a:Color => tColor
case a:Font => tFont
case a:HAlign.HAlign => tHAlign
case a:VAlign.VAlign => tVAlign
case a:TextStyle.TextStyle => tTextStyle
case _ => tUnknown
}
}
}
Run Code Online (Sandbox Code Playgroud)
我在哪里列举了一些东西:
object VAlign extends Enumeration {
type VAlign = Value
val top, middle, bottom = Value
}
object HAlign extends Enumeration {
type HAlign = Value
val left, center, right = Value
}
object TextStyle extends Enumeration {
type TextStyle = Value
val bold, italic, regular = Value
}
Run Code Online (Sandbox Code Playgroud)
那么,为什么会出现以下奇怪之处?:
scala> Type fromValue VAlign.bottom
res3: Type.Type = tHAlign
Run Code Online (Sandbox Code Playgroud)
另外,我怎样才能避免这种怪异?如何从值中进行类型匹配以区分不同的枚举?
我相信你面临着一个擦除路径依赖类型的问题(另见下面的编辑2).
让我们先简化一下这个例子:
object Enum1 extends Enumeration {
val A, B = Value
}
object Enum2 extends Enumeration {
val C, D = Value
}
def t(x : Any) {
println(x match {
case ab : Enum1.Value => "from first enum"
case cd : Enum2.Value => "from second enum"
case _ => "other"
})
}
Run Code Online (Sandbox Code Playgroud)
现在,与您观察到的相似,t(Enum1.A)并且t(Enum2.C)都打印"from first enum".
什么 - 我最初认为(见下面的编辑) - 这里发生的是,instanceOf使用:模式中的结果所产生的测试并没有区分两个路径相关的实例Value,所以第一种情况总是匹配.
解决此问题的一种方法是匹配枚举的值而不是这些值的类型:
def t2(x : Any) {
println(x match {
case Enum1.A | Enum1.B => "from first enum"
case Enum2.C | Enum2.D => "from second enum"
case _ => "other"
})
}
Run Code Online (Sandbox Code Playgroud)
编辑1实际上我的假设与规范所说的不符.根据语言规范(§8.2类型模式):
类型模式由类型,类型变量和通配符组成.类型模式T具有以下形式之一:
- 对C,pC或T #C类的引用.此类型模式匹配给定类的任何非null实例.请注意,如果给出了类的前缀,则与确定类实例相关.例如,模式pC仅匹配使用路径p作为pre fi x创建的类C的实例.底部类型scala.Nothing和scala.Null不能用作类型模式,因为它们在任何情况下都不匹配.
- [...]
如果我理解正确,那么instanceOf或者等同物应该区分这两种情况.
编辑2似乎是这个问题的结果.