我正在尝试在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的惯用方法(或任何实际工作的方式)都将非常感激!
答案 0 :(得分:2)
IterableLike (以及其他 XxxLike 特征)通过委托给每个集合必须特定的 Builder 来抽象返回类型类型。因此,你所尝试的是无法奏效的。
你可以创建一个通用的包装器 MyWrapperLike [A,B] 和几个特定的包装器 MySeqWrapper [A]扩展MyWrapperLike [A,Seq [A]] (同样适用于 Set , Map , List 等),即模仿Scala集合库的设计。