实现 scala 集合,以便 map、filter 等生成正确的类型 [英] Implement a scala collection so that map, filter, etc. produce the right type
问题描述
我正在尝试实现一个默认值地图,并且我希望过滤器、地图等在 DefaultingMap
上也尽可能生成 DefaultingMap
.这是我的初始实现:
I'm trying to implement a default valued map, and I'd like filters, maps, etc. over a DefaultingMap
to also produce a DefaultingMap
whenever possible. Here's my initial implementation:
class DefaultingMap[K, V](defaultValue: => V)
extends mutable.HashMap[K, V]
with mutable.MapLike[K, V, DefaultingMap[K, V]] {
override def empty = new DefaultingMap[K, V](defaultValue)
override def default(key: K): V = {
val result = this.defaultValue
this(key) = result
result
}
}
当我使用 filter
时,我得到 DefaultingMap
类型的对象,但当我使用 map
时不会:
I get objects of type DefaultingMap
when I use filter
, but not when I use map
:
scala> val counter = new DefaultingMap[Char, Int](0)
counter: DefaultingMap[Char,Int] = Map()
scala> for (c <- "ababcbbb") counter(c) += 1
scala> counter.filter{case (k, v) => v > 1}
res1: DefaultingMap[Char,Int] = Map((a,2), (b,5))
scala> counter.map{case (k, v) => (k, v * 2)}
res2: scala.collection.mutable.HashMap[Char,Int] = Map((a,4), (c,2), (b,10))
这两种方法的区别似乎在于 map
需要一个隐式的 CanBuildFrom
.所以我认为我需要在某处有一个 implicit def
来提供 CanBuildFrom
.我的第一个直觉是做 HashMap 中所做的事情:
The difference between these two methods seems to be that map
takes an implicit CanBuildFrom
. So I gather that I need to have an implicit def
somewhere to provide the CanBuildFrom
. My first intuition was to do what's done in HashMap:
object DefaultingMap extends generic.MutableMapFactory[DefaultingMap] {
def empty[K, V]: DefaultingMap[K, V] = // Not possible!
implicit def canBuildFrom[K, V]:
generic.CanBuildFrom[Coll, (K, V), DefaultingMap[K, V]] =
new MapCanBuildFrom[K, V]
}
我相信这会让它编译,但这种方法行不通,因为不可能定义 empty
方法 - 您需要知道 defaultValue
应该是什么是.如果我可以在类本身中定义 CanBuildFrom
而不是伴随对象,我会没事,因为 defaultValue
在那里可用.
I believe this would get it to compile, but this approach won't work because it's impossible to define the empty
method - you need to know what the defaultValue
should be. If I could define the CanBuildFrom
in the class itself, instead of the companion object, I would be okay because the defaultValue
is available there.
我怎样才能让它工作?
推荐答案
可变映射是 Scala 中的 Builder
,因此 MapFactory
默认采用输入问题以获取生成器.
Mutable maps are Builder
s in Scala, so the MapFactory
by default takes an empty map of the type in question to obtain a builder.
如果您有自定义地图构建规则,您可以做的一件事就是定义您的自定义工厂,类似于 collection.generic.MapFactory
.您必须以与那里类似的方式定义它,但是让 empty
方法和 newBuilder
方法都为 defaultValue
方法带一个额外的参数>.
If you have custom map build rules, one of the things you can do is to define your custom factory similar to collection.generic.MapFactory
. You would have to define it in a similar way like there, but make both the empty
method and the newBuilder
method take an additional argument for the defaultValue
.
类似的内容(如果您在建议的另一个链接中阅读了有关 Scala 2.8 集合 API 的更多信息,您会发现您不必为地图实现通用伴随对象):
Something along the lines of (if you read more about the Scala 2.8 collections API in the other link suggested, you'll find that you don't have to implement generic companion objects for maps):
import collection._
class DefaultingMap[K, V](val defaultValue: V)
extends mutable.HashMap[K, V]
with mutable.MapLike[K, V, DefaultingMap[K, V]] {
override def empty = new DefaultingMap(defaultValue)
}
object DefaultingMap {
def newBuilder[K, V](d: V): DefaultingMap[K, V] = new DefaultingMap[K, V](d)
implicit def canBuildFrom[K, V] =
new generic.CanBuildFrom[DefaultingMap[K, V], (K, V), DefaultingMap[K, V]] {
def apply(from: DefaultingMap[K, V]) = newBuilder[K, V](from.defaultValue)
def apply() = error("unsupported default apply")
}
}
object Main {
def main(args: Array[String]) {
println((new DefaultingMap[Int, Int](5)).defaultValue)
println(((new DefaultingMap[Int, Int](5)).map(x => x)).defaultValue)
}
}
打印:
$ scalac defaulting.scala
$ scala Main
5
5
我承认,这仍然不能解决无参数apply
的问题.
I admit, still, this does not solve the problem for the parameterless apply
.
这篇关于实现 scala 集合,以便 map、filter 等生成正确的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!