4

我正在使用 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 源代码,但我认为 contains 基本上会在第二个存在调用时实现。

4

3 回答 3

12

您没有覆盖 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 而非 State 的参数,您需要为其添加override关键字。

顺便说一句,您甚至不需要 == 方法,因为 Scala 会自动将其重新映射为 equals 方法!

于 2013-03-07T22:42:08.237 回答
4

您的equals方法没有被 调用contains,因为您没有覆盖 上的默认实现Any。对此的线索是编译器不会抱怨缺少override修饰符。

正确的方法签名是

override def equals(other: Any): Boolean

当您调用List(state).exists( _.equals (state.clone)时,它会解析为您的实现,因为编译器知道参数的类型是State。因此,它选择了专用于该类型的方法的重载变体。

的签名contains 始终采用Any类型参数,而不管 的类型参数如何List,因此方法调用将解析为 的默认实现equals

于 2013-03-07T22:41:40.423 回答
3

您对equalsand==的实施不应该是这样。出于这个原因,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
}
于 2013-03-07T22:51:08.220 回答