为什么以下情况会毫无例外地运行:
import scala.collection.mutable
class Label(val name: String) {
override def toString = s"Label($name)"
}
object Main extends App {
var map = mutable.Map[Label, Int]()
val ab = new Label("AB")
map += ab -> 1
println(map(ab))
}
以下将产生NoSuchElementException
:
import scala.collection.mutable
class Label(val name: String) {
override def toString = s"Label($name)"
}
object Main extends App {
var map = mutable.Map[Label, Int]()
map += new Label("AB") -> 1
println(map(new Label("AB")))
}
我一直无法找到解决方案,但我认为它必须与Scala中的平等和身份之间的差异有关。
答案 0 :(得分:0)
Scala中的平等和身份与Java一样。默认情况下,只有两个对象相同才对。类必须覆盖equals
和hashCode
,以便在散列数据中将两个不同的对象视为等效对象。默认情况下,如果不覆盖这些方法,则任何两个对象都不等于"并且不会替换为哈希键。
Java和Scala之间的主要区别在于==
运算符测试相等性,即使用equals
方法,而在Java ==
中测试身份。 (要在Scala中测试身份,请使用eq
运算符。)
因此,在您的第二个代码段中,new Label("AB")
的每个评估都会产生一个截然不同的非对象。查看第二次评估的结果无法解决第一次评估。
然而,在Scala中,不仅仅是Java,通常的做法是定义覆盖equals
和hashCode
的不可变对象。 Scala提供了" case classes"的概念,除了其他便利之外,还会自动覆盖这些方法。
您可以修改第二个代码段,只需将case
放在Label
的类定义之前。
scala> import scala.collection.mutable
import scala.collection.mutable
scala> case class Label(val name: String) {
| override def toString = s"Label($name)"
| }
defined class Label
scala> object Main extends App {
| var map = mutable.Map[Label, Int]()
| map += new Label("AB") -> 1
| println(map(new Label("AB")))
| }
defined object Main
scala> Main.main(Array.empty[String])
1
请注意,case类还会自动为类定义一个伴随对象,以及一个调用主构造函数的apply
方法。因此,不是写new Label("AB")
,而是简单地编写Label("AB")
。