我在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源代码,但我认为包含将基本上作为第二个存在的调用来实现。
答案 0 :(得分: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 not State类型的参数,您需要为其添加override
关键字。
答案 1 :(得分:4)
equals
未调用contains
方法,因为您未覆盖Any
上的默认实施。这样做的线索是编译器不会抱怨缺少override
修饰符。
正确的方法签名是
override def equals(other: Any): Boolean
当你调用List(state).exists( _.equals (state.clone)
时,它解决了你的实现,因为编译器知道参数的类型是State
。因此,它选择了专门针对该类型的方法的重载变体。
contains
的签名始终采用Any
类型的参数,无论List
的类型参数如何,因此方法调用将解析为equals
的默认实现。
答案 2 :(得分:3)
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
}