2012-02-19 21 views
10

Khi bạn khớp mẫu lại Danh sách, bạn có thể sử dụng Nil để kiểm tra danh sách trống. Tuy nhiên, nếu loại cơ bản là một Iterable, bạn vẫn có thể kiểm tra Nil, và nó sẽ phá vỡ cho Bộ trống rỗng, vv ... Xem sau phiên REPL:Làm thế nào để ngăn chặn kiểu kết hợp mẫu lỗi này và Nil

scala> val l: Iterable[Int] = List() 
l: Iterable[Int] = List() 

scala> l match { 
    | case Nil => 1 
    | case _ => 2 
    | } 
res0: Int = 1 

scala> val l: Iterable[Int] = Set() 
l: Iterable[Int] = Set() 

scala> l match { 
    | case Nil => 1 
    | case _ => 2 
    | } 
res2: Int = 2 

Câu hỏi là - làm thế nào tôi có thể ngăn chặn loại này vấn đề? Rõ ràng, nếu l là một List list, nó không có lỗi. Và nếu l thuộc loại Set, nó sẽ không biên dịch. Nhưng điều gì sẽ xảy ra nếu chúng ta có một lớp có một danh sách, hãy định nghĩa một hàm mà mô hình phù hợp theo cách này, và sau đó một người nào đó thay đổi lớp để có một biến lặp chung thay thế? Đây có phải là Nil so với _ mẫu phù hợp với một ý tưởng tồi nói chung?

+5

Loại phụ là một con dao hai lưỡi; sử dụng cẩn thận. –

Trả lời

8

Chuyển đổi scrutinee thành danh sách để loại bỏ sự nghi ngờ.

l.toList match { 
    case Nil => 1 
    case xs => 2 
} 
+1

Chuyển đổi chậm như thế nào nếu đó không phải là Danh sách? O (n) phải không? – dyross

+0

Đúng. '.toSeq' cũng là sufficent. '(Vector(): Seq [Int]) khớp với {case Nil => 0}'. – retronym

+0

Nhưng điều này phụ thuộc hoàn toàn vào thực tế là 'Nil.equals' được ghi đè lên để' Nil' bằng với bất kỳ seq rỗng nào. Điều này là không có giấy tờ, vì vậy tôi sẽ không dựa vào nó (vì vậy tốt hơn sử dụng 'toList' trên' toSeq' như trong câu trả lời của bạn, nó liên quan đến phép thuật ít hơn). –

11

Một khả năng là sử dụng một người bảo vệ:

scala> val xs: Iterable[Int] = Set() 
xs: Iterable[Int] = Set() 

scala> xs match { case xs if xs.isEmpty => 1 case _ => 2 } 
res0: Int = 1 

Một cách khác để làm điều này là sử dụng một if-else-biểu thức (hoạt động tốt nhất nếu bạn chỉ có một hoặc hai điều kiện để kiểm tra):

scala> if (xs.isEmpty) 1 else 2 
res1: Int = 1 
+0

Nếu khác là cách tôi đã kết thúc làm việc đó. Có vẻ như không phải là thành ngữ. – dyross

+0

Imho cách tốt nhất cho bộ sưu tập mẫu phù hợp – lisak

1

Dưới đây là một tùy chọn (ý định chơi chữ):

scala> val l: Iterable[Int] = List() 
l: Iterable[Int] = List() 

scala> l.headOption match { case None => 1; case Some(h) => 2 } 
res0: Int = 1 

này rất hữu ích trong trường hợp bạn mô hình phù hợp để có được những head như trong phổ biến List() match { case h :: t => ... } nhưng nó không phải là một danh sách, nó là một Iterable:: sẽ không thành công.

Tôi đã thêm câu trả lời này bởi vì tôi cho rằng nó khá phổ biến đối với mẫu khớp với bộ sưu tập để có đầu, nếu không bạn chỉ có thể kiểm tra với xs.isEmpty.

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