2010-09-24 19 views
28

Tôi có mã Scala sau đây.Sự nhầm lẫn khớp mẫu Scala với Tùy chọn [Bất kỳ]

import scala.actors.Actor 

object Alice extends Actor { 
    this.start 
    def act{ 
    loop{ 
     react { 
     case "Hello" => sender ! "Hi" 
     case i:Int => sender ! 0 
     } 
    } 
    } 
} 
object Test { 
    def test = { 
    (Alice !? (100, "Hello")) match { 
     case i:Some[Int] => println ("Int received "+i) 
     case s:Some[String] => println ("String received "+s) 
     case _ => 
    } 
    (Alice !? (100, 1)) match { 
     case i:Some[Int] => println ("Int received "+i) 
     case s:Some[String] => println ("String received "+s) 
     case _ => 
    } 
    } 
} 

Sau khi thực hiện Test.test, tôi nhận được kết quả:

scala> Test.test 
Int received Some(Hi) 
Int received Some(0) 

Tôi đã chờ đợi đầu ra

String received Some(Hi) 
Int received Some(0) 

lời giải thích là gì?

Là một câu hỏi thứ hai, tôi nhận được unchecked cảnh báo với các bên trên như sau:

C:\scalac -unchecked a.scala 
a.scala:17: warning: non variable type-argument Int in type pattern Some[Int] is unchecked since it is eliminated by erasure 
     case i:Some[Int] => println ("Int received "+i) 
      ^
a.scala:18: warning: non variable type-argument String in type pattern Some[String] is unchecked since it is eliminated by erasure 
     case s:Some[String] => println ("String received "+s) 
      ^
a.scala:22: warning: non variable type-argument Int in type pattern Some[Int] is unchecked since it is eliminated by erasure 
     case i:Some[Int] => println ("Int received "+i) 
      ^
a.scala:23: warning: non variable type-argument String in type pattern Some[String] is unchecked since it is eliminated by erasure 
     case s:Some[String] => println ("String received "+s) 
      ^
four warnings found 

Làm thế nào tôi có thể tránh những lời cảnh báo?

CHỈNH SỬA: Cảm ơn các đề xuất. ý tưởng Daniel là tốt đẹp, nhưng dường như không làm việc với các loại chung chung, như trong ví dụ dưới đây

def test[T] = (Alice !? (100, "Hello")) match { 
    case Some(i: Int) => println ("Int received "+i) 
    case Some(t: T) => println ("T received ") 
    case _ => 
} 

Sau đây lỗi cảnh báo là gặp phải: warning: abstract type T in type pattern T is unchecked since it is eliminated by erasure

Trả lời

36

Điều này là do gõ-chô bôi. JVM không biết bất kỳ tham số kiểu nào, ngoại trừ trên các mảng. Do đó, mã Scala không thể kiểm tra xem Option có phải là Option[Int] hoặc Option[String] - thông tin đó đã bị xóa.

Bạn có thể sửa mã của bạn theo cách này, mặc dù:

object Test { 
    def test = { 
    (Alice !? (100, "Hello")) match { 
     case Some(i: Int) => println ("Int received "+i) 
     case Some(s: String) => println ("String received "+s) 
     case _ => 
    } 
    (Alice !? (100, 1)) match { 
     case Some(i: Int) => println ("Int received "+i) 
     case Some(s: String) => println ("String received "+s) 
     case _ => 
    } 
    } 
} 

Bằng cách này bạn không thử nghiệm những gì các loại Option là, nhưng những gì các loại nội dung của nó được - giả sử có bất kỳ nội dung. A None sẽ rơi vào trường hợp mặc định.

+0

Cảm ơn! Các câu trả lời khác cũng tốt, bao gồm cả cách giải quyết được đề xuất bởi Kevin. Nhưng điều này có vẻ là cách thanh lịch nhất để sửa mã của tôi mà không cần viết lại nhiều. – Jus12

+0

Bạn có thể đề xuất cách giải quyết tương tự cho các loại chung không? như trong: 'def test [T] = (Alice!? (100," Hello ")) khớp với {case Some (t: T) => println (" T received "); case _ => println ("cái gì khác nhận được")} ' – Jus12

+1

@ Jus12 Bằng cách đó sẽ không hoạt động. Bạn sẽ cần có một 'm: Manifest [T]', sau đó làm một cái gì đó như 'case Some (t: T) nếu m.erasure.isAssignableFrom (t.getClass()) =>'. –

8

Mọi thông tin về thông số loại chỉ có sẵn tại biên dịch - thời gian, không phải lúc chạy (điều này được gọi là loại tẩy xoá). Điều này có nghĩa là khi thời gian chạy không có sự khác biệt giữa Option[String]Option[Int], vì vậy, bất kỳ mẫu nào khớp với loại Option[String], cũng sẽ khớp với Option[Int] vì thời gian chạy cả hai chỉ là Option.

Vì điều này hầu như không phải là ý của bạn, bạn sẽ nhận được cảnh báo. Cách duy nhất để tránh cảnh báo là không kiểm tra kiểu chung của một cái gì đó trong thời gian chạy (điều này là tốt vì nó không hoạt động như bạn muốn nó).

Không có cách nào để kiểm tra xem Option có phải là Option[Int] hoặc Option[String] khi chạy không (ngoài việc kiểm tra nội dung nếu đó là Some).

2

Như đã nêu, bạn đang chống lại việc xóa ở đây.

Đối với các giải pháp ... Đó là bình thường với diễn viên Scala để xác định các lớp học trường hợp đối với từng loại thông điệp mà bạn đang có khả năng để gửi:

case class MessageTypeA(s : String) 
case class MessageTypeB(i : Int) 

object Alice extends Actor { 
    this.start 
    def act{ 
    loop{ 
     react { 
     case "Hello" => sender ! MessageTypeA("Hi") 
     case i:Int => sender ! MessageTypeB(0) 
     } 
    } 
    } 
} 
object Test { 
    def test = { 
    (Alice !? (100, "Hello")) match { 
     case Some(MessageTypeB(i)) => println ("Int received "+i) 
     case Some(MessageTypeA(s)) => println ("String received "+s) 
     case _ => 
    } 
    (Alice !? (100, 1)) match { 
     case Some(MessageTypeB(i)) => println ("Int received " + i) 
     case Some(MessageTypeA(s)) => println ("String received " + s) 
     case _ => 
    } 
    } 
}