为什么不可变.Map扩展immutable.Map?

时间:2018-03-14 15:47:36

标签: scala

此代码有效:

@ mutable.Seq(1, 2).asInstanceOf[Seq[Int]]
res1: Seq[Int] = ArrayBuffer(1, 2)

但这并不是:

@ mutable.Map(1 -> 2).asInstanceOf[Map[Int, Int]]
java.lang.ClassCastException: scala.collection.mutable.HashMap cannot be cast
to scala.collection.immutable.Map
  ammonite.$sess.cmd1$.<init>(cmd1.sc:1)
  ammonite.$sess.cmd1$.<clinit>(cmd1.sc)

为什么mutable.Seq可以被视为不可变,而不是mutable.Map?我知道将一个可变的Seq投射到一个不可变的那个是#34;撒谎&#34;关于底层集合的可变性,但在某些情况下程序员知道更好 - 例如。从函数返回集合时,该函数使用可变列表来构建结果,但返回不可变值。

2 个答案:

答案 0 :(得分:6)

默认MapPredef中定义为

type Map[A, +B] = collection.immutable.Map[A, B]

所以它是明确的immutable,而mutable.Map不是它的子类。

与此相反,默认Seq直接在scala中定义为

type Seq[+A] = scala.collection.Seq[A] 

因此它是mutable.Seqimmutable.Seq的超类型。这就是您的第一个asInstanceOf未失败的原因:每个mutable.Seq也是collection.Seq

正如here所解释的那样,不指定Seq是否必须是可变的或不可变的决定与支持数组和变量有关。

In 2.13, the default Seq will become immutable, and a new type ImmutableArray will be introduced to deal with varargs.(感谢@SethTisue指出)

答案 1 :(得分:2)

主要问题是:

如果scala.collection.mutable.Mapscala.collection.immutable.Map的子类,那么前者也是后者。也就是说, mutable Map也是 immutable 。这有意义吗?

为了说明这一点,您可以将 mutable Map的实例传递给期望 immutable Map的函数或构造函数。唉,这两种类型有不同的语义:如果你在 immutable 版本中添加一个元素,你就会得到一个新的不可变的 Map实例返回;然而,如果你向 mutable 版本添加一个元素,它会改变该实例的内容 - 因此,它会有一个副作用

因此,如果你想编写一个纯的,引用透明的 RT )函数(即没有副作用的函数)接受不可变的 Map参数,你无法实现目标 - 任何人都可以通过传递 mutable {{1而实例。这会改变代码的含义,并可能导致各种问题。

函数式编程中, immutability RT 一样重要。通过确保两者不会混淆,需要不可变 Map的程序可以保证他们能够获得它们。

(当然,如果您明确想要编写可接受的代码,您可以请求其常见Map特征的实例。)