2012-08-07 30 views
2

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

我想是这样的:

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] 

更新: 在我选择的包装风格实现年底(装饰DP)完成了工作。我对斯卡拉的职业生涯只有6个月,所以我可能还没有正确理解特质的能力呢?!伟大的语言虽然!

+0

请告诉我们你是如何实例化地图。 – 2012-08-07 11:04:23

+1

您的最后一段听起来好像您想要更改单个已存在的对象的行为。你不能用特质来做到这一点,但你可以用对象的包装来做到这一点。但是,如果其他组件直接引用wrappee,那么它们将绕过您的包装。看看http://stackoverflow.com/questions/1913591/understanding-why-pimp-my-library-was-defined-that-way-in-scala和http://www.artima.com/weblogs /viewpost.jsp?thread=275135和https://github.com/kevinwright/Autoproxy-Lite – 2012-08-07 11:09:11

+0

首先编译器抱怨+不覆盖任何东西。尝试删除+或扩展具有+功能的类。 – 2012-08-07 11:15:10

回答

1

要么或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 with mytrait的变量mymap不会这样做。它会阻止它编译。

MyTrait必须出现在映射的创建中,而不仅仅是变量的类型声明中。那将是类似于new Map[A,B] with MyTrait[A,B](注意new)。

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

+0

感谢您的帮助。你可以添加一个更完整的代码示例,因为我仍然不完全清楚这一点。如果你可以用一个trait来显示地图的实例化(定义为只覆盖add方法,并调用super。+),那么我将非常感激它,并可以选择你的答案。谢谢 – ComethTheNerd 2012-08-07 10:11:58

0

您不能将特征添加到现有对象。 Trait不能动态添加,它们只能在创建对象时添加。 您可以:

  1. 使用pimp your library pattern,在你的问题的意见建议。但是,在这种情况下,您不能使用相同的方法,您需要使用自己的方法名称。
  2. 手工包装你的地图,这样你仍然可以使用+作为方法名。
  3. 创建对象的副本和特征添加到它。它可能导致性能问题,特别是如果原始地图很大。
+0

谢谢,但这并没有完全回答我所追求的。我编辑了我的问题以添加更多细节 – ComethTheNerd 2012-08-07 10:57:54

+0

是的,编辑完全改变了原始问题;)我编辑了我的答案。 – Nicolas 2012-08-07 11:35:10