用特征覆盖Scala贴图的添加方法

时间:2012-08-07 09:44:13

标签: scala map traits

给定Scala中的Map [String,Int],我想创建一个特性,允许我为add和get方法添加额外的逻辑。这样做的正确语法是什么? (注意:我也想在每种情况下调用super方法)

我尝试过类似的事情:

var mymap: Map[String, Int] with mytrait[String, Int] = Map[String, Int]()

trait mytrait[A, B] {

    abstract override def +[ B1 >: B] (kv: (A, B1)) : Map[A, B1] = { /* ... */ }

}

但是解释器抱怨所以我显然在语法上遗漏了一些东西,特别是使用了类型参数。

非常感谢您的帮助

更具体一点:我所拥有的是我的代码中已经存在的地图,所以不是重写我的程序的大块,我想在+方法中添加逻辑并获取Map的方法以便它每次将项目添加到程序中其他位置的地图时,都会执行额外的逻辑。因此,为什么我选择了一个特性来为地图添加功能

这是我目前的代码:

    trait RegManager[A, B] extends scala.collection.Map[A, B] {
    case class KeyAlreadyExistsException(e: String) extends Exception(e)

    abstract override def + [B1 >: B] (kv: (A, B1)): scala.collection.Map[A, B1] = {

        super.+[B1](kv)
    }

    abstract override def get(key: A): Option[B] = super.get(key)
    abstract override def iterator: Iterator[(A, B)] = super.iterator
    abstract override def -(key: A): scala.collection.Map[A, B] = super.-(key)
}



var regs = new scala.collection.Map[String, Int] with RegManager[String, Int]

更新 最后,我选择了一个包装器样式实现(Decorator DP)来完成工作。我只有6个月的时间进入我的Scala职业生涯,所以我可能还没有正确理解特征的能力呢?!很棒的语言!

2 个答案:

答案 0 :(得分:1)

MyTrait[A,B] extends Map[A,B]MyTrait[A,B] {this: Map[A,B] => ...


抱歉,实际上你不太可能以这种方式开展这项工作。

我的回答的第一部分与你的MyTrait声明没有引用Map的事实有关,因此它不可能覆盖Map的+。你需要像

这样的东西
trait MyTrait[A,B] extends Map[A,B] {
  abstract override def +[B1 >: B](kv: (A, B1)) : Map[A, B1] = {
    println("adding to map") // this is the new part
    super.+(kv) 
   }
}

然而,由于很多原因,这不会让你走得太远:

宣言中的

var mymap: Map[String, Int] with mytrait[String, Int] = Map[String, Int]()

Map[String, Int]()的类型为Map,与您的特征无关。声明mymap类型的变量Map with mytrait将不会如此。它只会阻止它编译。

MyTrait必须出现在地图的创建中,而不仅仅是变量的类型声明中。这就像new Map[A,B] with MyTrait[A,B](请注意new)。

但是,Map是一个特征,而不是具体的类,所以你必须引入一些具体的实现。如果你设法做到这一点,那么你必须要小心,+返回的新地图也混合了MyTrait类型(当然你的具体实现不太可能)。否则,一旦添加了一个元素,就会回到没有MyTrait的Map。

答案 1 :(得分:0)

您无法向现有对象添加特征。无法动态添加特征,只能在创建对象时添加特征。 你可以:

  1. 根据问题的评论中的建议使用pimp your library pattern。但是,在这种情况下,您不能使用相同的+ mnethod,您需要使用自己的方法名称。
  2. 手动换行地图,这样您仍然可以使用+作为方法名称。
  3. 创建对象的副本并为其添加特征。它可能导致性能问题,尤其是在原始地图很大的情况下。