Why doesn't mutable.Map extend immutable.Map?
此代码有效:
1 2
| @ mutable.Seq(1, 2).asInstanceOf[Seq[Int]]
res1: Seq[Int] = ArrayBuffer(1, 2) |
但这不是:
1 2 3 4 5
| @ 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转换为不可变的Seq是"说谎"底层集合的可变性,但是在某些情况下,程序员会更好地了解它。从使用可变列表构建结果但返回不可变值的函数返回集合时。
- 不确定"为什么",但是如果要将可变映射转换为不可变映射,请使用mutableMap.toMap;否则,请使用mutableMap.toMap。 mutableSeq.toSeq也是如此-这样,您无需了解基础实现。
-
可能相关:groups.google.com/forum /#!topic / scala-internals / g_-gIWgB8Os(可从默认的Scala Seq为mutable找到)。
默认Map在Predef中定义为
1
| type Map [A, +B ] = collection. immutable. Map[A, B ] |
因此它明确地是immutable,而mutable.Map不是它的子类。
与此相反,默认的Seq在scala中直接定义为
1
| type Seq [+A ] = scala. collection. Seq[A ] |
因此它是mutable.Seq和immutable.Seq的超类型。这就是为什么您的第一个asInstanceOf不会失败的原因:每个mutable.Seq也是一个collection.Seq。
如此处所述,不指定Seq必须是可变的还是不可变的决定与对数组和varargs的支持有关。
在2.13中,默认的Seq将变为immutable,并且将引入新的类型ImmutableArray来处理varargs。 (感谢@SethTisue指出)
- Predef中的Seq将更改为指向Scala 2.13中的collection.immutable.Seq
-
@SethTisue感谢您指出这一点,我在scala-lang.org上添加了关于此更改的(希望是相关的)链接。
-
啊,太糟糕了,能够将结果建立为ArrayBuffer并将其作为Seq返回而不将其复制到新的不可变结构中确实很方便!
-
@nornagon的"便捷",就像将灵魂卖给魔鬼以获得一些短期满足一样,是"便捷"的吗? ;)如果您不想将任何内容复制到不可变的结构中,则将返回类型显式声明为mutable.Seq,并且所有内容几乎都与以前一样。恕我直言,语言规范中不应包含任何集合。代替Seq或ImmutableArray,vararg机制应该是多态函数A* := [B](B, (B, A) => B) => B或类似的东西...不幸的是,这些函数不在Scala的核心中...
-
如果数组的元素在森林中发生变化,但没人在观察它,它真的可变吗? e?¤"
-
@nornagon只要可以保证没有人能够观察到它,它就具有参照透明性,这已经足够了。只要可能有人可以观察到该突变,它就不是参照透明的。如果不进行突变,那是一种约定。
主要问题是:
如果scala.collection.mutable.Map是scala.collection.immutable.Map的子类,那么前者也是-后者。也就是说,可变的Map也是不可变的。这有意义吗?
为了说明这一点,您可以将可变的Map的实例传递给期望不可变的Map的函数或构造函数。 ,,这两种类型具有不同的语义:例如,如果将元素添加到不可变版本中,则将返回新的不可变Map实例;但是,如果将元素添加到可变版本中,它将更改该实例的内容,因此会产生副作用。
因此,如果您想编写一个带有不变的Map参数的纯的,参照透明(RT)的函数(即没有副作用的函数),则您将无法实现目标,任何人都可以通过传递一个可变的Map实例来解决这个问题。然后,这将更改代码的含义,并可能导致各种形式的问题。
在函数式编程中,不变性和RT一样重要。通过确保两者不会混淆,需要不变的Map的程序可以保证它们将得到它们。
(当然,如果您明确想要编写将接受其中任何一个的代码,则可以请求其常见scala.collection.Map特性的一个实例。)