Scala:import不需要使用immutable.Map?

时间:2018-05-16 20:09:00

标签: scala scala-collections

我在这里学习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.Mapscala.collection.mutable._,则rimmutable.Map。如果import scala.collection.mutable._,则rmutable.Map

我有点困惑。有人可以帮忙解释一下吗?感谢

5 个答案:

答案 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.Mapscala.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

  
      
  1. 定义发生在同一编译单元中的package子句本地,继承或提供的定义和声明具有最高优先级。
  2.   
  3. 明确导入的优先级次高。
  4.   
  5. 通配符导入的优先级次高。
  6.   
  7. package子句提供的定义不在发生定义的编译单元中具有最低优先级。
  8.   

因此,由于第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

这是因为mscala.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