为什么没有apply-method就可以创建Map对象?

时间:2012-07-21 15:34:25

标签: scala map

C:\Users\John>scala
Welcome to Scala version 2.9.2 (Java HotSpot(TM) Client VM, Java 1.6.0_32).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.collection.mutable.Map
import scala.collection.mutable.Map

scala> Map()
res4: scala.collection.mutable.Map[Nothing,Nothing] = Map()

使用不含关键字Map()的{​​{1}}时,将调用相应的随播广告对象中的new方法。但Scala文档没有为可变映射列出apply方法(仅提供了从地图中检索值的apply方法)。

为什么上面的代码仍然有效?

3 个答案:

答案 0 :(得分:5)

它看起来像是scaladoc中的一个错误。对象apply中的 collection.mutable.Map方法(继承自GenMapFactory),但它没有出现在Map的文档中。这个问题似乎在the doc for upcomping 2.10中得到修复。

注意:您必须查看对象文档,而不是第一类。 apply中的方法class当然适用于现有的地图实例,并从中检索数据。

答案 1 :(得分:3)

scala.collection.immutable.Map()的伴随对象上有一个apply()方法。它继承自scala.collection.MapFactory。该方法采用可变数量的对参数,通常用作

Map("foo"->3, "bar"->4, "barangus"->5)

没有任何参数调用它显然也有效,但是比我更聪明的人必须解释为什么类型推理引擎会为它提出scala.collection.mutable.Map[Nothing,Nothing]

答案 2 :(得分:1)

正如sepp2k已在评论中提到,符号Map引用了Map的伴随对象,可让您访问其单个实例。在模式匹配中,这通常用于标识消息:

scala> case object Foo
defined module Foo

scala> def send[A](a: A) = a match { case Foo => "got a Foo" case Map => "got a Map" }
send: [A](a: A)String

scala> send(Map)
res8: String = got a Map

scala> send(Foo)
res9: String = got a Foo

如果您写Map(),则会调用对象apply的{​​{1}}方法。因为您没有给任何值插入Map,编译器无法推断任何类型,因此它必须使用bottom type - Map - 这是每种类型的子类型。虽然存在差异,但它是推断哪种类型不会破坏类型系统的唯一可能类型。如果Nothing不存在,则以下代码将无法编译:

Nothing

如果您查看scala> Map(1 -> 1) ++ Map() res10: scala.collection.mutable.Map[Int,Int] = Map(1 -> 1) 的类型签名,如下所示(source

++

您会注意到下限类型参数def ++[B1 >: B](xs: GenTraversableOnce[(A, B1)]): Map[A, B1] 。因为B1 >: B是所有内容的子类型(在我们的例子中是Nothing),编译器可以找到B(在我们的例子中是B1)并成功推断出类型签名为我们的地图。需要此下限是因为Int是协变的(source),

B

这意味着我们不允许将它作为方法参数传递(因为方法参数处于逆变位置)。如果方法参数不是逆变位置Liskov's substitution principle将不再由类型系统保留。因此,必须找到编译新类型(此处称为trait MapLike[A, +B, ...] ... )的代码。

正如B1已经指出的那样,Scaladoc 2.9中存在一些错误,这些错误在2.10中得到解决。不仅会显示一些错过的方法,而且还可以显示通过隐式转换添加的方法(例如,Array会显示2.10中的许多方法,这些方法未在2.9中显示。)