我在这里学习Scala https://scastie.scala-lang.org/iRJ8VOw7TySZ4KQ5qlWkdw。
import scala.collection.mutable
import scala.collection.mutable.ArrayBuffer
import scala.collection.mutable.SortedSet
// import scala.collection.immutable.Map // import not required to use immutable.Map
val m = Map((1 -> "a"), (2 -> "bb"))
val r = m.filter(_._1 > 1)
r // Map(2 -> bb): scala.collection.immutable.Map
println(r)
在上述代码中,r
的类型为scala.collection.immutable.Map
,即使scala.collection.immutable.Map
未导入scala.collection.mutable
已导入。
如果导入scala.collection.immutable.Map
和scala.collection.mutable._
,则r
为immutable.Map
。如果import scala.collection.mutable._
,则r
为mutable.Map
。
我有点困惑。有人可以帮忙解释一下吗?感谢
答案 0 :(得分:1)
第一个问题是Map
未从scale.collection.mutable
导入,因为您的import
声明存在问题。
更改
import scala.collection.mutable
到
import scala.collection.mutable._
或
import scala.collection.mutable.Map
和Map
将是mutable.Map
。
当您导入scale.collection.immutable.Map
和scala.collection.mutable._
immutable
Map
获胜时,因为它更具体。因此,最具体的import
获胜,如果出现平局,则会出现编译错误。
答案 1 :(得分:0)
默认情况下,Scala中的Map是不可变的。 你不能导入mutable.Map,所以它仍然是不可变的。 如果你像这样导入它应该工作:
import scala.collection.mutable.Map
如果导入scala.collection.immutable.Map和 scala.collection.mutable。,r是immutable.Map。如果进口 scala.collection.mutable。,r是mutable.Map。
最合格的导入声明获胜。
答案 2 :(得分:0)
默认 Scala为我们提供了不可变地图。有两种方式来创建可变地图:
**1.** Use import statement - *scala.collection.mutable._* to bring mutable map it into scope
**2.** Specify the full path to *scala.collection.mutable.Map*
使用导入“导入scala.collection.mutable ._ ”,您将导入所有可用的可变集合以及可变地图。
如果要添加 scala.collection.immutable.Map 以及 scala.collection.mutable ._ ,则告诉scala编译器使用全部可变集合,但在Map的情况下,使用不可变的。
答案 3 :(得分:0)
这里有五个不同的问题,让我们一个一个地处理它们。
为什么import collection.mutable
似乎无能为力?
如果我们从代码段中省略了不必要的详细信息,我们会获得:
import scala.collection.mutable
val r = Map(2 -> 3)
您问为什么r
仍然是scala.collection.immutable.Map
。
首先,请注意
import scala.collection.mutable
与
不同import scala.collection.mutable._
后者是通配符导入(可根据需要导入可变Map),而前者仅导入符号mutable
。因此,在您的代码中,只有符号mutable
可用,但这不会以任何方式影响Map
的含义。
即使没有导入任何内容,scala.collection.immutable.Map
来自哪里?
始终隐式导入Predef
(除非您使用编译器标志停用它)。有一个类型别名定义
type Map[A, +B] = collection.immutable.Map[A, B]
Predef中的,还有immutable.Map
的伴随对象的直接快捷方式:
val Map: collection.immutable.Map.type
允许您使用Map(...)
- 语法构建地图而不使用new
- 关键字。
为什么import collection.immutable.Map
优先于import collection.mutable._
?
specification states about the precedence of imports:
- 定义发生在同一编译单元中的package子句本地,继承或提供的定义和声明具有最高优先级。
- 明确导入的优先级次高。
- 通配符导入的优先级次高。
- package子句提供的定义不在发生定义的编译单元中具有最低优先级。
醇>
因此,由于第2点和第3点,显式导入
import scala.collection.mutable.Map
优先于通配符导入
import scala.collection.immutable._
为什么import collection.mutable._
使Map
变得可变?
现在,最后还有一点需要澄清:为什么mutable._
通配符导入优先于Predef
中的定义?这是一个简短的例子来说明它:
import scala.collection.mutable._
val m = Map()
println(m.getClass)
输出(可能有点令人惊讶):
class scala.collection.mutable.HashMap
在这一点上,规范似乎有点模糊,至少我找不到它说普通通配符导入掩盖了Predef中定义的地方。但是,here它说:
每个编译单元按给定的顺序隐式导入以下包:
- 包java.lang,
- 包scala和
- 对象scala.Predef,除非有一个引用scala.Predef的显式顶级导入。
稍后导入的成员会隐藏先前导入的成员。
我认为最后一句也涵盖scala.Predef
之后的导入,也就是显式通配符导入。这可能是import scala.collection.mutable._
掩盖Predef
中的定义的原因。
REPL中发生了什么?
当您尝试使用导入时,必须记住REPL计算每一行,就好像它在新的嵌套块中一样。这意味着,例如,脚本
import scala.collection.mutable._
import scala.collection.immutable._
Map()
将导致
error: reference to Map is ambiguous
但是如果你在REPL中逐个输入相同的行,那么就不会发生错误,你将得到一个不可变的Map
。这是因为在REPL中,上面的行被解释为
import scala.collection.mutable._
{
import scala.collection.immutable._
{
Map()
}
}
以便最后一次导入优先。我不确定Scastie是如何处理它的,可能它在那里也是一样的,所以这是一个额外的复杂因素,你必须记住。
答案 4 :(得分:-1)
tl; dr 使用import scala.collection.mutable.Map
这是因为m
是scala.collection.immutable.Map
的实例(默认行为)。在java中类似的行为隐式导入java.lang
包中的所有内容。
您导入的包不可变,这不会自动进入范围scala.collection.immutable.Map
以隐藏scala.collection.mutable.Map
为此,您应该import scala.collection.mutable.Map
import scala.collection.mutable
val m = Map((1 -> "a"), (2 -> "bb"))
println(m.getClass) // class scala.collection.immutable.Map$Map2
val mutableMap = mutable.Map((1->"A"), (2->"BB"))
println(mutableMap.getClass) // class scala.collection.mutable.HashMap
可选地
import scala.collection.mutable.Map
val m = Map((1 -> "a"), (2 -> "bb"))
println(m.getClass) // class scala.collection.mutable.HashMap