此代码有效:
@ 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;关于底层集合的可变性,但在某些情况下程序员知道更好 - 例如。从函数返回集合时,该函数使用可变列表来构建结果,但返回不可变值。
答案 0 :(得分:6)
默认Map
在Predef
中定义为
type Map[A, +B] = collection.immutable.Map[A, B]
所以它是明确的immutable
,而mutable.Map
不是它的子类。
与此相反,默认Seq
直接在scala
中定义为
type Seq[+A] = scala.collection.Seq[A]
因此它是mutable.Seq
和immutable.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.Map
是scala.collection.immutable.Map
的子类,那么前者也是后者。也就是说, mutable Map
也是 immutable 。这有意义吗?
为了说明这一点,您可以将 mutable Map
的实例传递给期望 immutable Map
的函数或构造函数。唉,这两种类型有不同的语义:如果你在 immutable 版本中添加一个元素,你就会得到一个新的不可变的 Map
实例返回;然而,如果你向 mutable 版本添加一个元素,它会改变该实例的内容 - 因此,它会有一个副作用。
因此,如果你想编写一个纯的,引用透明的( RT )函数(即没有副作用的函数)接受不可变的 Map
参数,你无法实现目标 - 任何人都可以通过传递 mutable {{1而实例。这会改变代码的含义,并可能导致各种问题。
在函数式编程中, immutability 和 RT 一样重要。通过确保两者不会混淆,需要不可变 Map
的程序可以保证他们能够获得它们。
(当然,如果您明确想要编写可接受的代码,您可以请求其常见Map
特征的实例。)