如何使用特定类型创建List的包装器

时间:2011-04-14 07:22:20

标签: list scala scala-2.8 scala-collections

我正在尝试使用特定类型(例如List)创建List[Int]的包装器,以便采用隐式CanBuildFrom参数的方法返回包装器的实例而不是{ {1}}。

一种可能的解决方案,感觉相当重量级,是:

List

有没有更好/更简单的方法来创建这样的包装器,还是我错过了import scala.collection._ import generic.{CanBuildFrom, SeqForwarder} import mutable.{Builder, ListBuffer} class MyList(list: List[Int]) extends immutable.LinearSeq[Int] with LinearSeqLike[Int, MyList] with SeqForwarder[Int] { override def newBuilder: Builder[Int, MyList] = MyList.newBuilder protected override def underlying = list } object MyList { def newBuilder: Builder[Int, MyList] = new ListBuffer[Int] mapResult(new MyList(_)) implicit def canBuildFrom: CanBuildFrom[MyList, Int, MyList] = { new CanBuildFrom[MyList, Int, MyList] { def apply(from: MyList) = from.newBuilder def apply() = newBuilder } } } val l1 = new MyList(List(1,2,3)) println(l1.isInstanceOf[MyList]) println(l1.map(_ + 1).isInstanceOf[MyList]) println(l1.filter(_ == 2).isInstanceOf[MyList]) 实现中的任何重要内容?

编辑:后续问题是:可以将整个包装逻辑放入MyList类或特征中,以便上述ListWrapper可以像这样实现:

MyList

2 个答案:

答案 0 :(得分:4)

据我所知,阅读本文:

http://www.scala-lang.org/docu/files/collections-api/collections-impl.html

如果你想要过滤器/地图/等,你的解决方案是最简单的。到MyList的所有返回实例。 newBuilder等操作需要filterCanBuildFrom等操作的隐式map可能会更改集合类型。

您在CanBuildFrom中应该做的是:

def apply(from: MyList) = from.newBuilder // call it on `from'

确保实际上具有map子类型的动态类型的静态类型MyList上的MyList将重复使用相同的动态类型。

修改:似乎缺少一些内容,因此map会返回List而不是MyList的实例:

val l1: LinearSeq[Int] = new MyList(List(1, 2, 3))
println(l1.map(_ + 1)) // prints List(2, 3, 4)

从链接文章中获取的RNA示例看起来也是如此。如果它具有静态类型IndexedSeq[Base]而不是RNA,则map上会返回一个向量。

编辑2 :看起来这是一个更普遍的问题,在this question中讨论过。

答案 1 :(得分:1)

关于如何通过类或特征混合包装器逻辑的后续问题,这就是我提出的:

import scala.collection._

trait ListWrapper[Elem, Repr <: ListWrapper[Elem, Repr]]
    extends immutable.LinearSeq[Elem]
    with LinearSeqLike[Elem, Repr]
    with generic.SeqForwarder[Elem] { self: Repr =>

  def wrapperCompanion: ListWrapperCompanion[Elem, Repr]

  override def newBuilder: mutable.Builder[Elem, Repr] =
    wrapperCompanion.newBuilder
}

trait ListWrapperCompanion[Elem, Repr <: ListWrapper[Elem, Repr]] {
  def apply(elems: TraversableOnce[Elem]): Repr

  def newBuilder: mutable.Builder[Elem, Repr] =
    new mutable.ListBuffer[Elem].mapResult(apply)

  def canBuildFromWrapper: generic.CanBuildFrom[Repr, Elem, Repr] = {
    new generic.CanBuildFrom[Repr, Elem, Repr] {
      def apply(from: Repr) = from.newBuilder
      def apply() = newBuilder
    }
  }
}

现在MyList可以通过以下方式实现:

class MyList(val underlying: List[Int]) extends ListWrapper[Int, MyList] {
  def wrapperCompanion = MyList
}

object MyList extends ListWrapperCompanion[Int, MyList] {
  def apply(elems: TraversableOnce[Int]) = new MyList(elems.toList)

  implicit def canBuildFrom = canBuildFromWrapper
}

这肯定比在MyList的定义中包含所有样板代码更好,但要使MyList只是List的包装器,仍然需要编写很多东西。