Конкретный конструктор для параметризованного типа

Я пытаюсь написать класс в Scala, который оборачивает (параметризованную) коллекцию и переопределяет ее метод foreach. То, что он делает с методом foreach, не имеет значения для целей этого вопроса, поэтому предположим, что он просто печатает каждый элемент по мере его посещения. Поэтому в идеале мы можем использовать оболочку следующим образом:

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

Ключ в том, что я хочу, чтобы это работало с любой итерацией; не просто список. Итак, моя первая попытка была похожа на следующую

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) }
        }  
 }

Однако, чтобы этот класс был конкретным, нам нужен метод итератора и метод newBuilder. Метод итератора не проблема, мы можем просто "украсть" итератор s следующим образом:

override def iterator = s.iterator

Проблема в том, когда я пытаюсь определить newBuilder. Мне нужен строитель, чтобы вернуть S[A]. Тем не менее, S[A] является параметризованной коллекцией, которая ограничена Iterable[A]. Таким образом, все мои попытки использования genericBuilder или получения компоновщика объекта-компаньона приводят к Iterable [A], а не к S[A], с соответствующими сообщениями об ошибках.

[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 

Как я могу получить конструктор, который строит определенный тип, S[A], а не общий ограниченный тип Iterable[A]? Это вообще возможно? Будем весьма благодарны за любую помощь в понимании идиоматического способа Scala сделать это (или любого другого способа, который действительно работает)!

1 ответ

IterableLike (и другие признаки XxxLike) абстрагируются по возвращаемому типу путем делегирования в Builder, который должен быть специфичным для каждого типа коллекции. Следовательно, то, что вы пытаетесь, не может работать.

Вы можете создать универсальную оболочку MyWrapperLike[A, B] и несколько специальных оболочек MySeqWrapper [A] extends MyWrapperLike [A, Seq [A]] (то же самое для Set, Map, List и т. Д.), Т.е. имитировать дизайн библиотека коллекции Scala.

Другие вопросы по тегам