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%確信しているわけではありませんクラスは最もスカラエスクな操作方法です。)

不変にしたいので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 に答える