Specific Builder for Parameterized Type

2019-03-31 04:28发布

I'm trying to write a class in scala that wraps a (parameterized) collection and overrides it's foreach method. What it does with the foreach method is unimportant for the purpose of this question, so lets say it just prints each element out as it's visited. So ideally, we'd be able to use the wrapper as follows:

scala> val a = List(1,2,3,4,5)
scala> val b = MyWrapper(a)
scala> b.foreach{ x => x }
1
2
3
4
5

The key is that I want this to work with any iterable; not just a list. So my first attempt was something like what follows

class MyWrapper[A, S[A] <: Iterable[A]]( val s: S[A] with IterableLike[A, S[A]]) 
      extends IterableLike[A, S[A]] {

        override def foreach[U](f: A => U): Unit = {
          iterator.foreach{ x => println(x); f(x) }
        }  
 }

However, for this class to be concrete, we need an iterator method and a newBuilder method. The iterator method is no problem, we can just "steal" s's iterator like so:

override def iterator = s.iterator

The problem is when I try to define newBuilder. I need the builder to return an S[A]. However, S[A] is a parameterized collection that is bounded by Iterable[A]. Thus all of my attempts using genericBuilder or getting the companion object's builder result in an Iterable[A] rather than an S[A], with the corresponding error messages

[error] method newBuilder in trait TraversableLike of type => scala.collection.mutable.Builder[A,S[A]] is not defined
[error] method seq in trait Parallelizable of type => scala.collection.TraversableOnce[A] is not defined 

How can I obtain a builder that builds the specific type, S[A], rather than the generic bounded type Iterable[A]? Is this even possible? Any help in understanding the idiomatic Scala way to do this (or any way that actually works) would be greatly appreciated!

1条回答
冷血范
2楼-- · 2019-03-31 04:49

IterableLike (and the other XxxLike traits) abstract over the return type by delegating to a Builder that has to be specific for each collection type. Hence what you are trying cannot work.

You could create a generic wrapper MyWrapperLike[A, B] and a couple of specific wrappers MySeqWrapper[A] extends MyWrapperLike[A, Seq[A]] (same for Set, Map, List, etc.), i.e. mimic the design of the Scala collection library.

查看更多
登录 后发表回答