2010-09-25 49 views
11

Câu hỏi này đã được hỏi trước đây trong danh sách gửi thư của người dùng không có câu trả lời xác nhận.ghi đè bằng phương thức() của Pair

scala> val T = new Pair(1, 2){ 
override def equals(obj:Any) = obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1} 
      } 

T: (Int, Int) = (1,2) 

scala> T match { 
     case (1, 1) => println("matched") 
     case _ => println("not matched") 
    } 

not matched 


scala> (1, 1) match { 
       case T => println("matched") 
       case _ => println("not matched") 
      } 

not matched 

scala> T == (1, 1) 
res15: Boolean = true 

Tôi cho rằng kết quả khớp mẫu không đổi phụ thuộc vào giá trị trả về "bằng", nhưng kết quả cho thấy không phải vậy, sau đó tiêu chí là gì?

Ai đó đã gợi ý rằng case (1, 1) => là mẫu hình vắt và sử dụng Tuple2.unapply để thay thế. vì vậy tôi đã thử các cách sau:

scala> Pair.unapply(T) 
res1: Option[(Int, Int)] = Some((1,2)) 

scala> Pair.unapply(T).get == (1, 1) 
res2: Boolean = true 

Bất cứ ai có thể giải thích lý do tại sao == có đúng không nhưng tôi không thể khớp với chúng?

Trả lời

2

Với độ phân giải #3888, tôi có thể đưa ra câu trả lời cuối cùng cho câu hỏi này.

  1. T match { case (1, 1) =>

    Không, nó không có gì để làm với unapply. Như extempore đã đề cập, case (1,1) => là một 'Tuple Pattern', một bí danh cho 'Constructor Pattern' của trường hợp class Tuple2, Nó chỉ khớp với giá trị được xây dựng như Tuple2 (1, 1) hoặc Pair (1, 1). mối quan tâm unapply là 'Extractor Pattern':.

    object Pair { 
        val T = new Pair(1,1){ 
         def unapply(p:(Int, Int)) :Boolean = this._1 == p._1 
        } 
        def main(args: Array[String]) = { 
         (1, 2) match { 
          case T() => println("matched") 
          case _ => println("not matched") 
         } 
        } 
    } 
    

    Bạn được "phù hợp" Chú ý () trong trường hợp quy định tại khoản

  2. (1, 1) match { case T => ...

    theo scala đặc tả , phần 8.1.5, đây là 'Mẫu Định danh Ổn định', case T khớp với bất kỳ giá trị v nào sao cho T == v. Vì vậy, chúng tôi NÊN được "khớp". Kết quả "không phù hợp" chỉ gây ra bởi lỗi trong việc triển khai trình biên dịch hiện tại.

13

Vấn đề với ví dụ của bạn là bạn chỉ ghi đè phương thức equals của lớp ẩn danh mà bạn xác định bộ dữ liệu cụ thể của mình là một phần của. Chúng ta hãy xem xét kỹ hơn những gì bạn đang làm khi chạy mã mà bạn đã đưa ra ở đây.

val p = new Pair(1, 2) { 
override def equals(obj:Any) = { 
    obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1 
    } 
} 

gì Scala làm ở đây là nó tạo ra một lớp ẩn danh mới mà mở rộng Pair và ghi đè bình đẳng của nó. Vì vậy, điều này tương đương với việc chạy mã sau:

class Foo extends Pair(1,2) { 
    override def equals(obj:Any) = { 
     obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1 
    } 
} 

val p = new Foo 

Và đây là nơi bạn có thể thấy chính xác vị trí của vấn đề! Định nghĩa của equals không đối xứng. p == (1,1) đánh giá là true(1,1) == p đánh giá là false! Điều này là do trước đây là tương đương với p.equals((1,1)) trong khi cái sau tương đương với (1,1).equals(p). Trong ví dụ bạn đã đưa ra, nó không hoạt động vì đối tượng trong trường hợp được so sánh với đối tượng được so khớp, và không phải là cách khác xung quanh. Do đó, như bạn đã chỉ ra, Pair.unapply(p).get == (1, 1) đánh giá là true, tuy nhiên (1,1) == Pair.unapply(p).get đánh giá là false và có vẻ như sau này được sử dụng khi đối sánh.

Tuy nhiên, trong mọi trường hợp tạo một bằng không đối xứng là một ý tưởng thực sự tồi tệ khi thực thi mã phụ thuộc vào thứ tự bạn so sánh các đối tượng. Ngoài ra, bằng bạn đã xác định có vấn đề khác - lỗi không thành công khi bạn cố so sánh p với bất kỳ Pair nào là không phải loại (Int, Int). Điều này là do, sau khi xóa bỏ loại (đó là cách JVM thực hiện generics), một Pair không còn được tham số bởi các loại thành phần của nó. Do đó, (Int, Int) có chính xác cùng loại như (String, String) và do đó, các mã sau đây sẽ thất bại với lỗi:

p == ("foo", "bar") 

như Scala sẽ cố gắng đúc một (String, String) một (Int, Int).

Nếu bạn muốn thực hiện chức năng này, điều đơn giản nhất bạn có thể làm là sử dụng mẫu hình thư viện pimp của tôi, vuốt một Pair. Tuy nhiên, bạn không nên gọi phương thức của mình equals. Gọi nó là một cái gì đó khác, như ~=. Tôi phải đi bây giờ, tuy nhiên khi tôi trở lại tôi có thể cung cấp cho bạn mã cho nó. Nó khá dễ dàng.Bạn nên xem xét việc triển khai equals trong một cặp và xóa phần so sánh đối số thứ hai :)

+0

Nhưng, mã của tôi đã kiểm tra cả hai hướng đối sánh: T khớp (1, 1) và (1, 1) khớp với T và ít nhất một thành công. – xiefei

3

Tôi phải nói rằng Scala lại làm tôi ngạc nhiên. Một số thử nghiệm khác cho thấy kết quả phụ thuộc vào ngữ cảnh đang chạy.

Nếu bạn chạy:

object Pair{ 
    def main(args:Array[String]) { 
     val T = new Pair(1, 2){ 
      override def equals(obj:Any)= obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1 
     } 

     (1, 1) match { 
      case T => println("matched") 
      case _ => println("not matched") 
     } 
    } 

} 

bạn nhận được: phù hợp

Và nếu bạn chạy:

object Pair extends Application { 
    val T = new Pair(1, 2){ 
     override def equals(obj:Any)= obj.isInstanceOf[(Int, Int)] && obj.asInstanceOf[(Int, Int)]._1 == this._1 
    } 

    (1, 1) match { 
     case T => println("matched") 
     case _ => println("not matched") 
    } 
} 

bạn nhận được: không phù hợp

Tôi đã luôn luôn nghĩ rằng có không có sự khác biệt giữa mã trong các phương thức main() và mã trong phần thân đối tượng, mở rộng đặc điểm ứng dụng. Thật kỳ lạ.

+0

Việc khởi tạo dường như không phải là một yếu tố, nhưng 'T' là một trường bên trong một' đối tượng' và một biến cục bộ bên trong một phương thức. –

+0

Sau khi di chuyển định nghĩa của T từ chính đến đối tượng, kết quả sẽ trở thành "không phù hợp". nhưng tại sao? – xiefei

+1

Trong nháy mắt, nó trông giống như một lỗi. – extempore

2

Tuples được đặc quyền trong trình ghép mẫu. Họ không phải là lớp học hàng ngày của bạn. Đó là trong spec, phần 8.1.7, "Tuple Patterns".

Khi bạn nói

(1, 1) match { case T ... 

Sau đó, bằng đang được gọi là, trên (1, 1), trong đó tất nhiên không nói cảm ơn, không bằng nhau.

Khi bạn nói

T match { case (1, 1) => ... 

Sau đó, bằng phương pháp của bạn bị bỏ qua vì mô hình tuple, và T._1 được so sánh với 1 và T._2 đến 1, và một lần nữa nó không phù hợp.

+0

Tại sao ví dụ đầu tiên của câu trả lời của xeifei lại trùng khớp? Tôi đã tự mình sao chép. –

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