2011-05-03 36 views
49

Tôi đã đọc rằng Scala'a case class xây dựng tự động tạo ra một phù hợp equalshashCode thực hiện. Mã được tạo chính xác trông như thế nào?hashCode trong trường hợp các lớp học trong Scala

+1

thể trùng lặp của (http://stackoverflow.com/ câu hỏi/4526706/mã-được-tạo-cho-một-bằng-hash-phương pháp-of-a-case-class) – Suma

Trả lời

67

Như giáo sư của tôi thường nói, chỉ có đoạn mã mới nói lên sự thật! Vì vậy, chỉ có một cái nhìn vào mã được tạo ra cho:

case class A(i: Int, s: String) 

Chúng tôi có thể hướng dẫn các trình biên dịch Scala để hiển thị chúng tôi mã tạo ra sau khi các giai đoạn khác nhau, ở đây sau khi typechecker:

% scalac -Xprint:typer test.scala 
[[syntax trees at end of typer]]// Scala source: test.scala 
package <empty> { 
    @serializable case class A extends java.lang.Object with ScalaObject with Product { 
    .. 
    override def hashCode(): Int = ScalaRunTime.this._hashCode(A.this); 
    ... 
    override def equals(x$1: Any): Boolean = A.this.eq(x$1).||(x$1 match { 
     case (i: Int,s: String)A((i$1 @ _), (s$1 @ _)) if i$1.==(i).&&(s$1.==(s)) => x$1.asInstanceOf[A].canEqual(A.this) 
     case _ => false 
    }); 


    override def canEqual(x$1: Any): Boolean = x$1.$isInstanceOf[A]() 
    }; 
} 

Vì vậy, bạn có thể thấy rằng việc tính toán mã băm được phân bổ cho ScalaRunTime._hashCode và sự bình đẳng phụ thuộc vào sự bình đẳng của các thành viên của nhóm trường hợp.

+4

Điều này không chỉ giải thích tốt, mà còn dạy tôi về '-Xprint: typer'. Cảm ơn rất nhiều! Điều duy nhất tôi đang bối rối là 'ScalaRunTime.this' có nghĩa là gì? Tại sao không chỉ đơn giản là 'ScalaRunTime._hashCode'? –

+0

Cú pháp 'ClassName.this' thường được sử dụng để truy cập một' this' bên ngoài từ bên trong một lớp bên trong (giống như trong Java). Không chắc chắn tại sao nó được in ở đây, có lẽ nó chỉ là cách mã được in khá bởi trình biên dịch. Nhưng đó chỉ là một đoán, bất cứ ai khác? –

46

Các tạo hashCode chỉ gọi scala.runtime.ScalaRunTime._hashCode, được định nghĩa là:

def _hashCode(x: Product): Int = { 
    val arr = x.productArity 
    var code = arr 
    var i = 0 
    while (i < arr) { 
    val elem = x.productElement(i) 
    code = code * 41 + (if (elem == null) 0 else elem.hashCode()) 
    i += 1 
    } 
    code 
} 

Vì vậy, những gì bạn nhận được là elem1 * 41**n + elem2 * 41**(n-1) .. elemn * 1, nơi n là arity của lớp trường hợp của bạn và elemi là những thành viên trong đó trường hợp lớp.

+0

Cảm ơn câu trả lời rõ ràng. Bây giờ tôi không biết liệu tôi có nên chấp nhận câu trả lời của bạn hay câu trả lời của Mirko hay không, từ đó tôi cũng đã học được các mẹo '-Xprint: typer' tiện dụng ... –

+0

Cùng với nhau, cả hai câu trả lời đều hoàn toàn trả lời câu hỏi :-) –

0

Dường như mọi thứ đã thay đổi; sử dụng của Mirko dụ case class A(i: Int, s: String) tôi nhận được: [? đang gì được tạo ra cho một phương pháp bình đẳng/hashCode của một lớp hợp]

override <synthetic> def hashCode(): Int = { 
     <synthetic> var acc: Int = -889275714; 
     acc = scala.runtime.Statics.mix(acc, i); 
     acc = scala.runtime.Statics.mix(acc, scala.runtime.Statics.anyHash(s)); 
     scala.runtime.Statics.finalizeHash(acc, 2) 
    }; 

override <synthetic> def equals(x$1: Any): Boolean = A.this.eq(x$1.asInstanceOf[Object]).||(x$1 match { 
    case (_: A) => true 
    case _ => false 
}.&&({ 
     <synthetic> val A$1: A = x$1.asInstanceOf[A]; 
     A.this.i.==(A$1.i).&&(A.this.s.==(A$1.s)).&&(A$1.canEqual(A.this)) 
    })) 
    }; 
Các vấn đề liên quan