【问题标题】:Create a custom scala collection where map defaults to returning the custom collection?创建一个自定义 scala 集合,其中地图默认返回自定义集合?
【发布时间】:2013-01-13 00:32:59
【问题描述】:

特征TraversableLike[+A, +Repr] 允许创建一个集合,其中一些 函数将返回Repr,而其他函数继续返回函数的类型参数That。有没有办法定义CustomCollection[A],其中map++ 和其他函数将默认ThatRepr,如果不是以其他方式推断?

这是一个代码 sn-p,希望能描述我想要的:

case class CustomCollection[A](list: List[A]) extends TraversableLike[A, CustomCollection[A]] {
  protected[this] def newBuilder = new CustomCollectionBuilder[A]
  def foreach[U](f: (A) => U) {list foreach f}
  def seq = list
}

class CustomCollectionBuilder[A] extends mutable.Builder[A, CustomCollection[A]] {
  private val list = new mutable.ListBuffer[A]()
  def += (elem: A): this.type = {
    list += elem
    this
  }
  def clear() {list.clear()}
  def result(): CustomCollection[A] = CustomCollection(list.result())
}

object CustomCollection extends App {
  val customCollection = CustomCollection(List(1, 2, 3))
  println(customCollection filter {x => x == 1}) // CustomCollection(1)
  println(customCollection map {x => x + 1}) // non-empty iterator
}

我希望最后一行是CustomCollection(2, 3, 4)

【问题讨论】:

  • 我只为 +1 om-nom-nom 登录,因为仅落后帖子三分钟。似乎没有“及时编辑!”带有竖起大拇指标志的按钮。

标签: scala collections type-inference scala-collections scala-2.10


【解决方案1】:

您需要设置一个提供精炼的CanBuildFrom 实例的伴生对象:

import collection.TraversableLike
import collection.generic.{CanBuildFrom, GenericCompanion, GenericTraversableTemplate,
  TraversableFactory}
import collection.mutable.{Builder, ListBuffer}

object CustomCollection extends TraversableFactory[CustomCollection] {
  def newBuilder[A] = new CustomCollectionBuilder[A]
  implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, CustomCollection[A]] = 
    new CanBuildFrom[Coll, A, CustomCollection[A]] {
       def apply(): Builder[A, CustomCollection[A]] = new CustomCollectionBuilder()
       def apply(from: Coll): Builder[A, CustomCollection[A]] = apply()
    }
}
case class CustomCollection[A](list: List[A]) extends Traversable[A]
with TraversableLike[A, CustomCollection[A]]
with GenericTraversableTemplate[A, CustomCollection] {
  override def companion: GenericCompanion[CustomCollection] = CustomCollection
  def foreach[U](f: A => U) { list foreach f }
  override def seq = list
}

class CustomCollectionBuilder[A] extends Builder[A, CustomCollection[A]] {
  private val list = new ListBuffer[A]()
  def += (elem: A): this.type = {
    list += elem
    this
  }
  def clear() {list.clear()}
  def result(): CustomCollection[A] = CustomCollection(list.result())
}

val customCollection = CustomCollection(List(1, 2, 3))
val f = customCollection filter {x => x == 1} // CustomCollection[Int]
val m = customCollection map {x => x + 1}     // CustomCollection[Int]

【讨论】:

  • 很好的答案!我有一种需要使用 cbf 的感觉,但我找不到最通用的方法。有没有什么地方可以阅读更多关于这样的集合 api 的细节? IE。我怎么知道除了扩展TraversableLike之外还需要扩展GenericTraversableTemplate
  • @dicarlo2 - 我通常会查看与我正在做的最相似的类的源代码并复制它们混合的内容。我发现这比没有其他方法更可靠确切地知道每个特征提供了哪些功能(以及您希望如何解决所有菱形继承模式)。
  • @RexKerr Heh,这就是我通常做的事情,在发布问题后,我在不得不离开计算机之前就收到了TraversableFactory 的问题,但谁知道我会有多少文件已经翻遍了所有菱形的继承模式。太糟糕了,没有更好的参考资料,而且文档并不总是能说明每个特征之间的关系。
  • @dicarlo2 - 我认为收藏库是“这张图片中有多少个三角形”的变相谜题之一。
  • 最好的可能是保留现有的集合,如果您需要额外的功能,请尝试使用 Scala 2.10 的 IsTraversableLike 助手添加它们的类型类样式。
猜你喜欢
  • 2023-03-19
  • 2017-05-17
  • 1970-01-01
  • 2013-07-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多