2011-10-21 12 views
3

私は値の型を表すための列挙型クラスを持っています。このクラスのコードは非常に単純です:Scala列挙型で間違った(?)型の一致

私はmathingの列挙を持って
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 

、どのように発生しましたこの奇妙さを避けることはできますか?異なる列挙型を区別するために値から型マッチングを行うにはどうすればよいですか?

答えて

7

私はあなたが消去されたパス依存型の問題に直面していると思います(下記の編集2も参照してください)。

のは、最初の例を単純化してみましょう:両方のプリント"from first enum"、同様にあなたが観察したものに、

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の2パス依存のインスタンス間の違いを作る、そうしないことです最初のケースは常に一致します。この問題を回避するために

一つの方法は、値の代わりに、これらの値のタイプの列挙のに一致させることです。

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への参照。この型パターンは、指定されたクラスのnull以外のインスタンスに一致します。クラスのプレフィックス が与えられていれば、これはクラス のインスタンスの決定に関係することに注意してください。例えば、パターンp.Cは、パスpをプリフィックスとして作成されたクラスCの クラスCのインスタンスにのみ一致します。一番下の数字は 型scala.Nothingとscala.Nullはいずれも一致しないので、型パターンとして使用することはできません。
  • [...]

私はこれを正しく理解していれば、instanceOfまたは同等 2例を区別する必要があります。


編集2this issueの結果であると思われます。

+0

あなたが提供した2番目のリンクを読むと、スケーラの列挙がバグであるように見えます。私は実際には、現在の状態のためにjava enumを使用することを検討しています。だから、これは私が望んでいた答えではありませんが、少なくとも私は今どこに立っているのかを知っています。ありがとう! –

+0

2番目の考えでは、各列挙体に共通の基本クラスを使用し、列挙型の値として継承するオブジェクトを使用します。値は、作成時に基本クラスのコンパニオンオブジェクトに登録されます。これにより、必要な型の構文と、列挙値の取得が可能になります。 –

+1

@LightningIsMyName Enumerationを使用すべきではないと一般的なことが分かっているので、封印された抽象クラスを拡張するケースオブジェクトを使用する必要があります。 –