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

发布于 2024-12-11 17:30:29 字数 1158 浏览 0 评论 0原文

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

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

另​​外,我怎样才能避免这种奇怪的情况?如何根据值进行类型匹配以区分不同的枚举?

I have an enumeration class for representing types of values. The code of the class is pretty simple:

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

Where I have the mathing enumerations:

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
}

So, why does the following weirdness occur?:

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

Also, how can I avoid this weirdness? How can I do type matching from a value to distinguish the different enumerations?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

嘿哥们儿 2024-12-18 17:30:29

我相信您面临着删除路径相关类型的问题(另请参见下面的编辑 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) 都从第一个枚举打印 " “

我最初认为(请参阅下面的编辑)- 这里发生的是,在模式中使用 : 所产生的 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"
  })
}

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

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

  • 对 C、pC 或 T #C 类的引用。此类型模式匹配给定类的任何非空实例。注意前缀
    类别的(如果给出)与确定类别相关
    实例。例如,模式 pC 仅匹配以下实例
    以路径 p 作为前缀创建的类 C。底部
    类型 scala.Nothing 和 scala.Null 不能用作类型模式,
    因为无论如何它们都不会匹配任何内容。
  • [...]

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


编辑 2 似乎是此问题的结果。

I believe you're facing a problem of erased path-dependent types (see also Edit 2 below).

Let's simplify the example first:

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

Now, similarly to what you observed, t(Enum1.A) and t(Enum2.C) both print "from first enum".

What — I originally thought (see edit below) — is happening here is that the instanceOf test that results from using the : in the pattern doesn't make the difference between the two path-dependent instantiations of Value, so the first case always matches.

One way to work around this is to match on the values of the enumeration instead of the type of these values:

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

Edit 1 Actually my hypothesis does not match what the spec says. According to the language specification (§8.2 Type Patterns):

Type patterns consist of types, type variables, and wildcards. A type
pattern T is of one of the following forms:

  • A reference to a class C, p.C, or T #C. This type pattern matches any non-null instance of the given class. Note that the prefix
    of the class, if it is given, is relevant for determining class
    instances. For instance, the pattern p.C matches only instances of
    classes C which were created with the path p as prefix. The bottom
    types scala.Nothing and scala.Null cannot be used as type patterns,
    because they would match nothing in any case.
  • [...]

If I understand this correctly, the instanceOf or equivalent should distinguish between the two cases.


Edit 2 Seems to be a consequence of this issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文