簡體   English   中英

Scala List.contains(x)返回false,但exists(_。== x)返回true

[英]Scala List.contains(x) return false, but exists(_.== x) returns true

我在Scala中使用一些簡單的數據結構和集合,我注意到我認為是奇怪的行為。 這是對象:

class State (protected val trackmap: Map[Int, List[String]]) {

  override def clone : State = {
    new State(Map() ++ trackmap)
  }

  override def toString = { "State: " + trackmap.toString }

  def equals (other: State) : Boolean = {
    //println("Comparing " + trackmap + " to " + other.trackmap)
    trackmap == other.trackmap  

  }

  def == (other: State) : Boolean = {
    this equals other
  }
}

我的相關測試:

  test("state equality") {
    val state = new State( Map(1 -> List("engine"), 2 -> List("a"), 3 -> List("b")) )

    expect(true) { state equals state.clone }
    expect(true) { state == state.clone }
    expect(false) { state == new State(Map(1 -> List("a"))) }
    expect(false) { state equals new State(Map(1 -> List("a"))) }

    expect(true) { List(state).exists( _.equals (state.clone) )}
    expect(true) { List(state).exists( _.== (state.clone) )}
    expect(true) { List(state).contains( state.clone )}
  }

所有這些都通過了,除了最后一個,我期望它應該通過。 我沒有看過Scala源代碼,但我認為包含將基本上作為第二個存在的調用實現。

你沒有覆蓋Scala的實際 equals方法,這就是為什么它表現得很奇怪。 像這樣重寫你的equals方法,事情應該有效:

override def equals (other: Any) : Boolean = {
    other match{
      case that: State =>
        //println("Comparing " + trackmap + " to " + other.trackmap)
        trackmap == that.trackmap
      case _ => false
    }
}

請參閱,Scala中的equals方法采用Any not State類型的參數,您需要為其添加override關鍵字。

順便說一句,你甚至不需要==方法,因為Scala會自動將其重新映射為equals方法!

您的equals方法不會被contains調用,因為您沒有覆蓋Any上的默認實現。 這樣做的線索是編譯器不會抱怨缺少override修飾符。

正確的方法簽名將是

override def equals(other: Any): Boolean

當你調用List(state).exists( _.equals (state.clone) ,它解析為你的實現,因為編譯器知道參數的類型是State 。因此它選擇了專用於方法的重載變量。那種類型。

contains的簽名始終采用Any類型的參數,無論List的類型參數如何,因此方法調用將解析為equals的默認實現。

你的equals==實現不是應該的。 出於這個原因,Scala有case類。

那么你的課就像這樣

case class State(protected val trackmap: Map[Int, List[String]]) {

  override def clone: State = {
    new State(Map() ++ trackmap)
  }

  override def toString = { "State: " + trackmap.toString }
}

如果您想手動實現它們,則需要實現Equals特性。 並覆蓋以下方法:

override def canEqual(other: Any) = 
  other.isInstanceOf[State]

override def equals(other: Any) = {
  other match {
    case that: State => (that canEqual this) && trackmap == that.trackmap
    case _ => false
  }
}

override def hashCode() = {
  val prime = 41
  prime + trackmap.hashCode
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM