2009-12-03 31 views
90

Tôi đang làm phù hợp với một số trường hợp và muốn xử lý hai trường hợp theo cùng một cách. Một cái gì đó như thế này:Đối sánh nhiều trường hợp với các lớp học trong scala

abstract class Foo 
case class A extends Foo 
case class B(s:String) extends Foo 
case class C(s:String) extends Foo 


def matcher(l: Foo): String = { 
    l match { 
    case A() => "A" 
    case B(sb) | C(sc) => "B" 
    case _ => "default" 
    } 
} 

Nhưng khi tôi làm điều này tôi nhận được lỗi:

(fragment of test.scala):10: error: illegal variable in pattern alternative 
    case B(sb) | C(sc) => "B" 

tôi có thể lấy nó làm việc của tôi loại bỏ các thông số từ định nghĩa của B và C nhưng làm thế nào tôi có thể kết hợp với các params?

Trả lời

123

Hình như bạn không quan tâm đến các giá trị của các thông số String, và muốn đối xử với B và C là như nhau, do :

def matcher(l: Foo): String = { 
    l match { 
    case A() => "A" 
    case B(_) | C(_) => "B" 
    case _ => "default" 
    } 
} 

Nếu bạn phải, phải, phải trích xuất các tham số và đối xử với họ trong khối mã tương tự, bạn có thể:

def matcher(l: Foo): String = { 
    l match { 
    case A() => "A" 
    case bOrC @ (B(_) | C(_)) => { 
     val s = bOrC.asInstanceOf[{def s: String}].s // ugly, ugly 
     "B(" + s + ")" 
    } 
    case _ => "default" 
    } 
} 

Mặc dù tôi cảm thấy nó sẽ sạch hơn nhiều đến yếu tố đó ra thành một phương pháp:

def doB(s: String) = { "B(" + s + ")" } 

def matcher(l: Foo): String = { 
    l match { 
    case A() => "A" 
    case B(s) => doB(s) 
    case C(s) => doB(s) 
    case _ => "default" 
    } 
} 
+0

Mặc dù ví dụ của tôi không hiển thị nhưng tôi cần các thông số đó. Có vẻ như tôi sẽ phải sử dụng một vật thể. Cảm ơn! – timdisney

+4

Có lý do scala không cho phép "trường hợp A (aString) | trường hợp B (aString) => println (aString)"? Có vẻ như miễn là loại aString giống hệt nhau cho cả A và B, nó sẽ được cho phép. Ví dụ cuối cùng của bạn có vẻ như tốt hơn là không sao chép các trường hợp B và C. –

+30

Tôi sẽ hướng dẫn thêm cho bạn. Tôi nghĩ sẽ tốt hơn nếu có 'trường hợp A (x) | B (x) => println (x) 'được cho phép trong đó loại' x' được đặt thành giới hạn trên trong hệ thống kiểu của bất kỳ sản phẩm A (x) và B (x) nào. –

4

Vâng, nó không thực sự hợp lý, phải không? B và C là loại trừ lẫn nhau, vì vậy sb hoặc sc bị ràng buộc, nhưng bạn không biết cái nào, vì vậy bạn cần thêm logic lựa chọn để quyết định sử dụng (cho rằng chúng bị ràng buộc với một Option [String], không một chuỗi).

l match { 
    case A() => "A" 
    case B(sb) => "B(" + sb + ")" 
    case C(sc) => "C(" + sc + ")" 
    case _ => "default" 
    } 

Hoặc này:: Vậy có gì đạt được trong này là

l match { 
    case A() => "A" 
    case _: B => "B" 
    case _: C => "C" 
    case _ => "default" 
    } 
+0

Điều gì sẽ xảy ra nếu bạn không quan tâm liệu B hoặc C có được khớp không? Nói trong đoạn mã sau: 'args match { trường hợp Array (" - x ", hostArg) => (hostArg, true); case Array (hostArg, "-x") => (hostArg, true) } ' Tuy nhiên, tôi thấy đó không phải là trường hợp phổ biến và việc tạo phương thức cục bộ là một phương án thay thế. Tuy nhiên, nếu phương án thay thế thuận tiện, thì có rất ít điểm trong việc lựa chọn trường hợp thay thế. Trên thực tế, trong một số phương ngữ ML bạn có một tính năng tương tự và bạn vẫn có thể liên kết các biến, miễn là (IIRC) vì mỗi biến được ràng buộc với cùng loại trên cả hai lựa chọn thay thế. – Blaisorblade

+0

Bạn đã đúng. Nếu bạn chỉ quan tâm đến các loại và không phải là các giá trị cũng như loại nào đã được trình bày, thì kết hợp dựa trên kiểu loại bỏ là có ý nghĩa và có sẵn. –

8

Có một vài cách mà tôi có thể nhìn thấy để đạt được những gì bạn đang sau đó, nếu bạn có một số tương đồng giữa trường hợp các lớp học. Đầu tiên là để các lớp vỏ mở rộng một đặc tính khai báo tính phổ biến, thứ hai là sử dụng một kiểu cấu trúc để loại bỏ sự cần thiết phải mở rộng các lớp chữ hoa của bạn.

object MuliCase { 
    abstract class Foo 
    case object A extends Foo 

    trait SupportsS {val s: String} 

    type Stype = Foo {val s: String} 

    case class B(s:String) extends Foo 
    case class C(s:String) extends Foo 

    case class D(s:String) extends Foo with SupportsS 
    case class E(s:String) extends Foo with SupportsS 

    def matcher1(l: Foo): String = { 
    l match { 
     case A  => "A" 
     case s: Stype => println(s.s); "B" 
     case _  => "default" 
    } 
    } 

    def matcher2(l: Foo): String = { 
    l match { 
     case A   => "A" 
     case s: SupportsS => println(s.s); "B" 
     case _   => "default" 
    } 
    } 

    def main(args: Array[String]) { 
    val a = A 
    val b = B("B's s value") 
    val c = C("C's s value") 

    println(matcher1(a)) 
    println(matcher1(b)) 
    println(matcher1(c)) 

    val d = D("D's s value") 
    val e = E("E's s value") 

    println(matcher2(d)) 
    println(matcher2(e)) 
    } 
} 

Phương pháp kiểu cấu trúc tạo cảnh báo về xóa, hiện tại tôi không biết cách loại bỏ.

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