我正在尝试使用特定类型(例如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
答案 0 :(得分:4)
据我所知,阅读本文:
http://www.scala-lang.org/docu/files/collections-api/collections-impl.html
如果你想要过滤器/地图/等,你的解决方案是最简单的。到MyList
的所有返回实例。 newBuilder
等操作需要filter
,CanBuildFrom
等操作的隐式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
的包装器,仍然需要编写很多东西。