Неверное (?) Совпадение типов в перечислениях Scala - PullRequest
3 голосов
/ 21 октября 2011

У меня есть класс перечисления для представления типов значений. Код класса довольно прост:

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

Где у меня есть перечисления mathing:

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

Кроме того, как мне избежать этой странности? Как я могу сделать сопоставление типов со значением, чтобы различать различные перечисления?

1 Ответ

7 голосов
/ 21 октября 2011

Я полагаю, что вы столкнулись с проблемой стертых зависимых от пути типов (см. Также Редактирование 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, который получается в результате использования : в шаблоне, не делает различий между двумя зависимыми от пути экземплярами Value, поэтому первый случай всегда совпадает.

Одним из способов решения этой проблемы является сопоставление значений перечисления вместо type следующих значений:

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 На самом деле моя гипотеза не соответствует тому, что говорит spec . Согласно спецификации языка (§8.2 Типовые шаблоны):

Типовые шаблоны состоят из типов, переменных типов и подстановочных знаков. Тип шаблон T имеет одну из следующих форм:

  • Ссылка на класс C, p.C или T #C. Этот тип шаблона соответствует любому ненулевому экземпляру данного класса. Обратите внимание, что префикс класса, если он указан, имеет значение для определения класса экземпляров. Например, шаблон p.C соответствует только экземплярам классы C, которые были созданы с путем p как префикс. Дно типы scala.Nothing и scala.Null нельзя использовать в качестве шаблонов типов, потому что в любом случае они ничего не будут соответствовать.
  • [...]

Если я правильно понимаю, instanceOf или эквивалентный должен различать два случая.

<ч />

Редактировать 2 Кажется, это следствие этой проблемы .

...