Scala List.contains(x)返回false,但exists(==x)返回true
我正在Scala中处理一些简单的数据结构和集合,我注意到了我认为奇怪的行为。这是目标:Scala List.contains(x)返回false,但exists(==x)返回true,list,scala,collections,contains,exists,List,Scala,Collections,Contains,Exists,我正在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 equa
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基本上会作为第二个exists调用来实现。您的
equals
方法没有被contains
调用,因为您没有覆盖Any
上的默认实现。这方面的线索是,编译器不会抱怨缺少重写
修饰符
正确的方法签名是
override def equals(other: Any): Boolean
当您调用List(state).exists(u.equals(state.clone)
)时,它解析为您的实现,因为编译器知道参数的类型是state
。因此它选择了专用于该类型的方法的重载变量
contains
的签名始终采用类型为Any
的参数,而不管列表的类型参数是什么,因此方法调用将解析为equals
的默认实现,因为您没有覆盖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和=
的实现不是它应该的样子。因此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
}
请注意,这也可以通过以下事实来证明:List(state).exists(==state.clone)
返回true
,List(state).exists(==state.clone:Any))
返回false
。在equals
实现中使用模式匹配将比isInstanceOf
/asInstanceOf
组合更加惯用。是的,我现在就解决它。谢谢你的建议(我对Scala还是有点Javaish)