具有对象键的可变映射

时间:2016-09-21 01:04:45

标签: scala object dictionary

为什么以下情况会毫无例外地运行:

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中的平等和身份之间的差异有关。

1 个答案:

答案 0 :(得分:0)

Scala中的平等和身份与Java一样。默认情况下,只有两个对象相同才对。类必须覆盖equalshashCode,以便在散列数据中将两个不同的对象视为等效对象。默认情况下,如果不覆盖这些方法,则任何两个对象都不等于"并且不会替换为哈希键。

Java和Scala之间的主要区别在于==运算符测试相等性,即使用equals方法,而在Java ==中测试身份。 (要在Scala中测试身份,请使用eq运算符。)

因此,在您的第二个代码段中,new Label("AB")的每个评估都会产生一个截然不同的非对象。查看第二次评估的结果无法解决第一次评估。

然而,在Scala中,不仅仅是Java,通常的做法是定义覆盖equalshashCode的不可变对象。 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")