2012-10-29 10 views
23

Widziałem pewną liczbę twierdzeń, że wyliczanie Scala nie jest bezpieczne. Jak to nie jest bezpieczne? Wydaje się, że jest to bezpieczne w oczywisty sposób, ponieważ nie można przekazać wartości jednego Wyliczenia do innego Wyliczenia.Scala: w jaki sposób Wyliczenie nie jest bezpieczne?

Jakie pułapki lub rzeczy należy unikać przy wyliczaniu?

Odpowiedz

33

Jest pół-bezpieczny. To, że jest bezpiecznym typem, jest fikcją kompilatora, więc łatwo go złamać. Na przykład:

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) 
    ... 

Dobra, chłopcy nie są dziewczynami.

Teraz spróbujmy z wyliczeń:

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 

Czekaj, co?

To fikcja prowadzi do innych dziwnych zachowań:

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 

Uh, w porządku, dzięki?

A potem, ponieważ kompilator nie bardzo rozumiem Enumeration jako własnej konstrukcji, nie może pomóc w taki sposób można się było spodziewać:

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) 
    ... 

Więc jeśli używasz go w stosunkowo ograniczonych sposobów dokładnie zgodnie z przeznaczeniem zapewnia bezpieczeństwo typu. Ale nie ma mocy i solidności innych wzorców, takich jak ten:

// 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" } 
         ^

Dzięki, kompilator!

Powiązane problemy