Scala Enumerations中的错误(?)类型匹配

Bar*_*kin 3 enumeration scala

我有一个枚举类来表示值的类型.该类的代码非常简单:

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)

另外,我怎样才能避免这种怪异?如何从值中进行类型匹配以区分不同的枚举?

Phi*_*ppe 7

我相信你面临着一个擦除路径依赖类型的问题(另见下面的编辑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似乎是这个问题的结果.