扩展内置集合,内置方法问题 [英] Extending built-in collections, issues with built-in methods

查看:48
本文介绍了扩展内置集合,内置方法问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am a Scala novice so forgive me if this is a stupid question, but here goes...

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

Imagine I wish to create an extended Map type that includes additional methods. I can see a few ways to do this. The first would be with composition:

class Path[V](val m: Map[V, Int]) {
  // Define my methods
}

另一个是通过继承,例如

Another would be via inheritance, e.g.

class Path[V] extends Map[V, Int] {
// Define my methods
}

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

Finally, I've also considered the "trait" route, e.g.

trait Path[V] extends Map[V, Int] {
// Define my methods
}

构图有点尴尬,因为你必须不断地引用里面的东西.继承是相当自然的,但对我来说有一个皱纹(一秒钟内更多).Traits 似乎是一种非常优雅的方式来做到这一点,使用with"构造确实很好,但它对我来说也有问题.

Composition is a bit awkward because you are constantly having to reference the thing inside. Inheritance is a fairly natural but there is a wrinkle for me (more in a sec). Traits seems like a really elegant way to do this and using the "with" construct it is really nice but it also has an issue for me.

我遇到的问题是使用 ++ 之类的方法.他们返回一张新地图.所以假设上面提到的我的方法"希望向地图添加一些东西(只是一个例子,我知道地图已经有了这个),例如

The wrinkle I'm running into is with methods like ++. They return a new map. So let's say the "my method" referred to above wishes to add something to the map (just an example, I know the map already has this), e.g.

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

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

This generates an error because the return type is not Path[V]. Now I know I can use "with" on a new instance to add the Path[V] trait. But I don't control the construction of the new map here. Is there any way to add the Path[V] trait? I thought about creating a new immutable map that was pre-populated and then tagging on a "with Path[V]", but there is no such constructor I can use to create the pre-populated map.

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

I suspect (although I haven't confirmed it) that I would have a similar issue using inheritance. I could add a new method to add a new entry to the map, but I would not get back a "Path[V]" which is what I want. The compositional approach seems to be the only way to go here.

我希望这很清楚.评论?

I hope this is clear. Comments?

推荐答案

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

Perhaps the simplest way to do this is to use the MapProxy trait:

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)
}

通过允许您将 Path 视为 Map,这消除了组合方法的尴尬:

This eliminates the awkwardness with the compositional approach by allowing you to treat a Path as if it is a 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)

如果包含从 MapPath(在 Path 伴随对象中定义)的隐式转换,那么您也可以将 Map 就好像它是一个 Path:

If you include the implicit conversion from Map to Path (defined in the Path companion object), then you can also treat a Map as if it is a Path:

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

有一个类似的 SeqProxy trait 用于向 Seq 添加行为.

There is a similar SeqProxy trait for adding behavior to a Seq.

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

In the more general case, a solution is to use the pimp my library pattern. This related question has an example.

这篇关于扩展内置集合,内置方法问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆