实现 scala 集合,以便 map、filter 等生成正确的类型 [英] Implement a scala collection so that map, filter, etc. produce the right type

查看:42
本文介绍了实现 scala 集合,以便 map、filter 等生成正确的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现一个默认值地图,并且我希望过滤器、地图等在 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 Builders 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屋!

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