【问题标题】:"Too many arguments" error in Scala superclass constructor but not in REPLScala超类构造函数中的“参数过多”错误,但REPL中没有
【发布时间】:2012-10-31 19:27:40
【问题描述】:

我正在编写一个类,它使用一些自定义构造函数逻辑扩展了 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")
               ^

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

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

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

class MyMap extends HashMap[Int, String]

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

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

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


此链接about implementing Map with concrete types 是相关的。


【问题讨论】:

    标签: scala constructor compiler-errors


    【解决方案1】:

    你在这里得到一个错误,因为当你写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)
    

    【讨论】:

    • 对。这就说得通了。我仍然不确定如何获得我想要的构造函数调用。再想一想,一个等价的问题可能是“我如何为HashMap 调用复制构造函数?”
    • 是真的吗,apply 方法是从GenMapFactory 而不是直接从companion object 来的?
    • @om-nom-nom: eclipse 的超链接功能说是 ;) 我会编辑我的帖子。
    • @W.P.McNeill:你为什么想要一个自己的类来提供初始元素?是不是创建完类后就不能添加了?
    • 修改原始问题以回答@sschaef 的先前评论
    猜你喜欢
    • 1970-01-01
    • 2013-02-19
    • 2012-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 2013-03-16
    • 1970-01-01
    相关资源
    最近更新 更多