【问题标题】:Wrong(?) type matching in Scala EnumerationsScala 枚举中的错误(?)类型匹配
【发布时间】:2011-10-21 20:48:35
【问题描述】:

我有一个用于表示值类型的枚举类。类的代码很简单:

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
    }
  }
}

我有数学枚举的地方:

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
}

那么,为什么会出现以下奇怪现象?:

scala> Type fromValue VAlign.bottom
res3: Type.Type = tHAlign

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

【问题讨论】:

    标签: scala enumeration


    【解决方案1】:

    我相信您正面临擦除路径相关类型的问题(另请参阅下面的编辑 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"
      })
    }
    

    现在,与您观察到的类似,t(Enum1.A)t(Enum2.C) 都打印 "from first enum"

    我最初认为(请参阅下面的编辑)在这里发生的事情是 instanceOf 测试由在模式中使用 : 产生的,并不会在 @ 的两个依赖于路径的实例之间产生差异987654329@,所以第一个 case 总是匹配的。

    解决此问题的一种方法是匹配枚举的,而不是这些值的类型

    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"
      })
    }
    

    编辑 1 实际上我的假设与spec 所说的不符。根据语言规范(§8.2 类型模式):

    类型模式由类型、类型变量和通配符组成。一种 模式 T 是以下形式之一:

    • 对 C、p.C 或 T #C 类的引用。此类型模式匹配给定类的任何非空实例。注意前缀 类的,如果给出的话,与确定类有关 实例。例如,模式 p.C 只匹配 以路径 p 作为前缀创建的类 C。底部 类型 scala.Nothing 和 scala.Null 不能用作类型模式, 因为它们在任何情况下都不匹配。
    • [...]

    如果我理解正确,instanceOf 或等效项应该区分这两种情况。


    Edit 2似乎是this issue的结果。

    【讨论】:

    • 阅读您提供的第二个链接确实看起来好像 scala 枚举有问题。由于当前的情况,我实际上正在考虑使用 java 枚举。所以,这不是我所希望的答案,但至少我知道我现在的立场。谢谢!
    • 再想一想,我将为每个枚举使用一个公共基类,从它继承的对象作为枚举的值。这些值将在创建时向基类的伴随对象注册。这将允许我想要的类型语法,以及获取枚举值。
    • @LightningIsMyName 普遍的共识似乎是您不应该使用枚举,而应该使用扩展密封抽象类的案例对象
    • @LuigiPlinge:你这么说很有趣,因为我刚刚写完(没有检查其他人做了什么)然后我看到了你的评论 :) 谢谢你的确认 - 现在我知道我了m 在正确的轨道上
    猜你喜欢
    • 1970-01-01
    • 2012-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-10
    • 2017-06-23
    • 2023-02-08
    • 1970-01-01
    相关资源
    最近更新 更多