1

我正在编写一个类,它使用一些自定义构造函数逻辑扩展了 Scala 的不可变映射。作为一个简单的例子,假设我想要一个整数映射到初始化为的字符串1 -> "one", 2 -> "two"。在 REPL 中,我可以编写以下内容。

scala> import collection.immutable.HashMap
import collection.immutable.HashMap

scala> HashMap[Int, String](1->"one", 2->"two")
res0: scala.collection.immutable.HashMap[Int,String] = Map(1 -> one, 2 -> two)

在我的程序中,我想使用相同的构造函数调用,但是当我尝试将它放在类定义行中时,我得到一个“构造函数的参数太多”错误。

scala> class MyMap extends HashMap[Int, String](1->"1", 2->"2")
<console>:8: error: too many arguments for constructor HashMap: ()scala.collection.immutable.HashMap[Int,String]
   class MyMap extends HashMap[Int, String](1->"1", 2->"2")
               ^

鉴于调用超类构造函数的方法是在类定义中,我认为HashMap在 REPL 中创建 a 的任何表达式也应该在定义中起作用,但是我在这里缺少一些微妙之处。

(我认为在HashMap这里扩展具体类而不是特征是正确的做法,因为我想使用默认的地图实现。扩展HashMap是我在 Java 中所做的,但我不能 100% 确定扩展具体集合classes 是最 Scalaesque 的操作方式。)

因为我想MyMap是不可变的,所以我需要在构造函数时指定初始值。apply我可以尝试在伴随对象的函数内部进行初始化,如下所示:

class MyMap extends HashMap[Int, String]

object MyMap {
  def apply() = new MyMap ++ List(1 -> "one", 2 -> "two")
}

MyMap()返回一个不可变的映射而不是一个MyMap.

初始化的正确方法是MyMap什么?


这个关于使用具体类型实现 Map 的链接是相关的。


4

1 回答 1

7

你在这里得到一个错误,因为当你写的时候你Map()没有调用Map. 相反,您调用它的伴随对象的 apply 方法(或更准确地说,它的超类之一的 apply 方法。请参阅 om-nom-noms 注释):

scala> Map(1 -> "one")
res0: scala.collection.immutable.Map[Int,String] = Map(1 -> one)

scala> Map.apply(1 -> "one")
res1: scala.collection.immutable.Map[Int,String] = Map(1 -> one)

如果您想拥有自己的Map实现,则需要创建自己的实现。我想出的最简单的事情是:

object MyMap {
  def apply(ts: (Int, String)*): MyMap[Int, String] = new MyMap(ts.toMap)
  def apply(): MyMap[Int, String] = apply(1 -> "one", 2 -> "two")
}

class MyMap[A, B] private(t: Map[Int, B]) extends Map[Int, B]  {
  private val internalMap = t
  def +[B1 >: B](kv: (Int, B1)) = new MyMap(internalMap + kv)
  def -(key: Int) = new MyMap(internalMap - key)
  def get(key: Int) = internalMap.get(key)
  def iterator = internalMap.iterator
}

scala> MyMap()
res1: MyMap[Int,String] = Map(1 -> one, 2 -> two)
于 2012-10-31T19:41:08.980 回答