Я пытаюсь реализовать карту со значением по умолчанию , и мне бы хотелось, чтобы фильтры, карты и т. Д. Вместо DefaultingMap
также создавали DefaultingMap
, когда это возможно. Вот моя первоначальная реализация:
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
}
}
Я получаю объекты типа DefaultingMap
, когда я использую filter
, но не когда я использую 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:
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
доступен там.
Как мне заставить это работать?