2012-10-29 29 views
23

Tôi đã nhìn thấy một số xác nhận rằng Scala Enumeration không phải là loại an toàn. Làm thế nào là nó không an toàn? Có vẻ như loại an toàn theo cách rõ ràng ở chỗ bạn không thể chuyển giá trị của một liệt kê cho một liệt kê khác.Scala: cách liệt kê không an toàn?

Những cạm bẫy hoặc những điều cần tránh khi liệt kê là gì?

Trả lời

33

Nó bán an toàn. Đó là loại an toàn là một trình biên dịch viễn tưởng, do đó, nó rất dễ dàng để phá vỡ. Ví dụ:

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

Được rồi, con trai không phải là con gái.

Bây giờ chúng ta hãy thử với kiểu liệt kê:

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 

Chờ, gì?

tiểu thuyết này dẫn đến những hành vi kỳ lạ khác:

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, được rồi, nhờ?

Và rồi kể từ khi biên dịch không thực sự hiểu Enumeration như cấu trúc riêng của nó, nó không thể giúp bạn theo những cách bạn có thể mong đợi:

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

Vì vậy, nếu bạn sử dụng nó theo những cách tương đối hạn chế chính xác như dự định, nó cung cấp loại an toàn. Nhưng nó không có sức mạnh và sức mạnh của các mẫu khác, như thế này:

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

Cảm ơn, trình biên dịch!

Các vấn đề liên quan