23

Scala Enumeration がタイプ セーフではないという主張をいくつか見てきました。タイプセーフではないのはどうしてですか?ある Enumeration の値を別の Enumeration に渡すことができないという点で、明らかにタイプ セーフのようです。

Enumeration の落とし穴や避けるべきことは何ですか?

4

1 に答える 1

33

半安心です。タイプセーフであることはコンパイラのフィクションであるため、簡単に破ることができます。例えば、

trait Parent
class Boy extends Parent { override def toString = "boy" }
class Girl extends Parent { override def toString = "girl" }
def f(g: Girl) = g.toString

scala> f((new Boy).asInstanceOf[Girl])
java.lang.ClassCastException: Boy cannot be cast to Girl
    at .<init>(<console>:15)
    ...

いいですか、男の子は女の子ではありません。

それでは、列挙を試してみましょう。

object Test extends Enumeration { val One, Two = Value }
object Probar extends Enumeration { val Uno, Dos = Value }
def h(tv: Test.Value) = tv.toString

scala> h((Probar.Uno).asInstanceOf[Test.Value])
res0: java.lang.String = Uno

待って、何?

このフィクションは、他の奇妙な動作につながります。

def h(pv: Probar.Value) = pv.toString  // Add this to the other h in a :paste

method h:(pv: Probar.Value)java.lang.String and
method h:(tv: Test.Value)java.lang.String at line 9
have same type after erasure: (pv: Enumeration#Value)java.lang.String
           def h(pv: Probar.Value) = pv.toString

ええと、わかりました、ありがとう?

そして、コンパイラはEnumerationそれ自体の構造を実際には理解していないため、期待するような方法であなたを助けることはできません:

scala> def oops(tv: Test.Value) = tv match { case Test.One => "okay" }
oops: (tv: Test.Value)java.lang.String
// No incomplete match warning?  Okay....

scala> oops(Test.Two)
scala.MatchError: Two (of class scala.Enumeration$Val)
    at .oops(<console>:8)
    ...

したがって、意図したとおりに比較的限定された方法で使用すると、タイプ セーフが提供されます。ただし、次のような他のパターンほど強力で堅牢ではありません。

// In REPL, :paste the next three lines
sealed trait Foo
object Bar extends Foo
object Baz extends Foo

scala> def safe(f: Foo) = f match { case Bar => "okay" }
<console>:9: warning: match is not exhaustive!
missing combination            Baz

        def safe(f: Foo) = f match { case Bar => "okay" }
                           ^

ありがとう、コンパイラ!

于 2012-10-29T21:26:59.633 に答える