extending scala collections with new attribute
If I have a new collection with an additional attribute, e.g. :
class NewColl(var name: String, var values: Vector[Int])
extends IndexedSeq[Int] with IndexedSeqLike[Int, NewColl] {...}
how do I define canBuildFrom
and newBuilder
(cf. here) such that if:
var v1 = NewColl("foo",Vector(1,2,3))
var v2 = v1 filter(_ > 1)
var开发者_Python百科 v3 = v1 map(_ + 1)
then v2.name=="foo"
and v3.name=="foo"
?
Try this:
class NewColl(val name: String, val values: Vector[Int])
extends IndexedSeq[Int] with IndexedSeqLike[Int, NewColl] with SeqForwarder[Int] {
override def newBuilder: Builder[Int, NewColl] = NewColl.newBuilder(name)
protected override def underlying = values
}
object NewColl {
def apply(name: String, elems: Vector[Int]) = new NewColl(name, elems)
implicit def canBuildFrom: CanBuildFrom[NewColl, Int, NewColl] = {
new CanBuildFrom[NewColl, Int, NewColl] {
def apply(from: NewColl) = from.newBuilder
def apply() = newBuilder(defaultName)
}
}
private def newBuilder(name: String) = Vector.newBuilder[Int].mapResult(vector => new NewColl(name, vector))
private def defaultName: String = error("no default name")
}
Note that I've changed your var
s into val
s here to be consistent with an immutable collection. SeqForwarder
has been mixed in to avoid implementing a list of methods that would all forward to the same method on values
. newBuilder
has been implemented on the companion object and needs a String
parameter.
Note that sometimes, collections are free to call apply()
on the CanBuildFrom
without specifying the originating collection. In that case, you either have to provide a default name, or (like here) throw an exception (permissible only if you're not designing a library and control the use of your new collection).
See also that question.
精彩评论