扩展内置集合,内置方法的问题

Mic*_*ler 2 scala traits

我是Scala新手,请原谅我,如果这是一个愚蠢的问题,但是这里......

想象一下,我希望创建一个包含其他方法的扩展Map类型.我可以看到几种方法来做到这一点.第一个是组成:

class Path[V](val m: Map[V, Int]) {
  // Define my methods
}
Run Code Online (Sandbox Code Playgroud)

另一种是通过继承,例如

class Path[V] extends Map[V, Int] {
// Define my methods
}
Run Code Online (Sandbox Code Playgroud)

最后,我还考虑了"特质"路线,例如

trait Path[V] extends Map[V, Int] {
// Define my methods
}
Run Code Online (Sandbox Code Playgroud)

构图有点尴尬因为你经常不得不引用里面的东西.遗传是相当自然的,但我有一个皱纹(更多的是一秒).Traits看起来像是一种非常优雅的方式,并且使用"with"构造它非常好但它对我来说也有问题.

我遇到的皱纹是用像++这样的方法.他们返回一张新地图.所以让我们说上面提到的"我的方法"希望在地图上添加一些东西(只是一个例子,我知道地图已经有了这个),例如

trait Path[V] extends Map[V,Int] {
    def addOne(v: V, i: Int): Path[V] = this + (v -> i)
}
Run Code Online (Sandbox Code Playgroud)

这会生成错误,因为返回类型不是Path [V].现在我知道我可以在新实例上使用"with"来添加Path [V]特征.但我不控制这里新地图的构造.有没有办法添加Path [V]特征?我考虑创建一个预先填充的新不可变映射,然后在"with Path [V]"上进行标记,但是没有这样的构造函数可以用来创建预先填充的映射.

我怀疑(虽然我还没有确认)我会有类似的问题使用继承.我可以添加一个新方法来向地图添加一个新条目,但我不会得到一个"Path [V]"这就是我想要的.组合方法似乎是走到这里的唯一方法.

我希望这很清楚.评论?

Aar*_*rup 6

也许最简单的方法是使用MapProxy特征:

import collection._

class Path[V](val self: Map[V, Int]) extends MapProxy[V, Int] {
   // without the companion object below
   def addOne(v: V, i: Int): Path[V] = new Path(this + (v -> i))
   // with the companion object below
   def addOne(v: V, i: Int): Path[V] = this + (v -> i)
   // other methods
}

// this companion object is not strictly necessary, but is useful:
object Path {
   implicit def map2path[V](map: Map[V, Int]): Path[V] = new Path(map)
}
Run Code Online (Sandbox Code Playgroud)

通过允许您将a Path视为以下内容,可以消除组合方法的尴尬Map:

scala> new Path(Map("a" -> 1)) + ("b" -> 2)
res1: scala.collection.Map[java.lang.String,Int] = Map((a,1), (b,2))

scala> new Path(Map("a" -> 1)).get("a")
res2: Option[Int] = Some(1)
Run Code Online (Sandbox Code Playgroud)

如果包含隐式转换MapPath(在Path随播对象中定义),那么您还可以将其Map视为Path:

scala> Map("a" -> 1).addOne("b", 2)
res3: Path[java.lang.String] = Map((a,1), (b,2))
Run Code Online (Sandbox Code Playgroud)

SeqProxy向a添加行为有类似的特征Seq.

在更一般的情况下,解决方案是使用pimp my library模式.这个相关问题有一个例子.