2015-08-19 57 views
11

從源代碼scala/Equals.scalahere):canEqual()在scala.Equals特質

package scala 
trait Equals extends scala.Any { 
    def canEqual(that: scala.Any): scala.Boolean 
    def equals(that: scala.Any): scala.Boolean 
} 

在本文檔中,它說:

應該從每個孔被調用的方法-designed equals方法是打開的,可以在子類中重寫。

我隨機挑選了一個延伸了scala.Equals的類,它足夠簡單易懂。我選擇了scala.Tuple2[+T1, +T2],這擴大了特徵scala.Product[T1, T2],這反過來又擴展了特徵scala.Product,這繼而擴展了特徵scala.Equals

不幸的是,似乎因爲scala.Tuple2情況下類,所述canEqual()equals()方法是自動生成的,因此不能在源代碼中scala/Tuple2.scalahere)中找到。

我的問題是:

  • 當它是一個很好的時間延長特質scala.Equals
  • canEqual()應該如何實施?
  • equals()中使用canEqual()的最佳做法(或樣板)是什麼?

在此先感謝! PS:如果它很重要,我使用的是Scala 2.11.7。

回答

16

canEquals方法用於覆蓋期望equals應該是對稱的 - 也就是說,當(且僅當)a.equals(b)爲真,則b.equals(a)也應如此。將類的實例與子類的實例進行比較時,會出現問題。例如。

class Animal(numLegs: Int, isCarnivore: Boolean) { 
    def equals(other: Any) = other match { 
    case that: Animal => 
     this.numLegs == that.numLegs && 
     this.isCarnivore == that.isCarnivore 
    case _ => false 
    } 
} 

class Dog(numLegs: Int, isCarnivore: Boolean, breed: String) extends Animal(numLegs, isCarnivore) { 
    def equals(other: Any) = other match { 
    case that: Dog => 
     this.numLegs == that.numLegs && 
     this.isCarnivore == that.isCarnivore && 
     this.breed == that.breed 
    case _ => false 
    } 
} 

val cecil = new Animal(4, true) 
val bruce = new Dog(4, true, "Boxer") 
cecil.equals(bruce) // true 
bruce.equals(cecil) // false - cecil isn't a Dog! 

爲了解決這個問題,確保兩個實體是相同的(子)輸入的equals定義使用canEqual

class Animal(numLegs: Int, isCarnivore: Boolean) { 
    def canEqual(other: Any) = other.isInstanceOf[Animal] 
    def equals(other: Any) = other match { 
    case that: Animal => 
     that.canEqual(this) && 
     this.numLegs == that.numLegs && 
     this.isCarnivore == that.isCarnivore 
    case _ => false 
    } 
} 

class Dog(numLegs: Int, isCarnivore: Boolean, breed: String) extends Animal(numLegs, isCarnivore) { 
    def canEqual(other: Any) = other.isInstanceOf[Dog] 
    def equals(other: Any) = other match { 
    case that: Dog => 
     that.canEqual(this) && 
     this.numLegs == that.numLegs && 
     this.isCarnivore == that.isCarnivore && 
     this.breed == that.breed 
    case _ => false 
    } 
} 

val cecil = new Animal(4, true) 
val bruce = new Dog(4, true, "Boxer") 
cecil.equals(bruce) // false - call to bruce.canEqual(cecil) returns false 
bruce.equals(cecil) // false 
+1

謝謝您的回答!我認爲訣竅是'that.canEqual(this)'而不是'this.canEqual(that)',它會以相反的方式進行檢查以確保equals()的有效性。你知道生成的case類版本是否遵循了你在這裏顯示的相同模式?謝謝! –

+0

@ SiuChingPong-AsukaKenji-我相信它確實,但我不確定。 – Shadowlands