Scala 2.13的迁移指南解释说,它Traversable
已被删除,Iterable
应该改用它。对于一个使用访问者在树的类中实现foreach
方法的项目来说,这种变化特别烦人:Node
case class Node(val subnodes: Seq[Node]) extends Traversable[Node] {
override def foreach[A](f: Node => A) = Visitor.visit(this, f)
}
object Visitor {
def visit[A](n: Node, f: Node => A): Unit = {
f(n)
for (sub <- n.subnodes) {
visit(sub, f)
}
}
}
object Main extends App {
val a = Node(Seq())
val b = Node(Seq())
val c = Node(Seq(a, b))
for (Node(subnodes) <- c) {
Console.println("Visiting a node with " + subnodes.length + " subnodes")
}
}
输出:
Visiting a node with 2 subnodes
Visiting a node with 0 subnodes
Visiting a node with 0 subnodes
迁移到 Scala 2.13 的一个简单修复方法是首先将访问过的元素存储在remaining
缓冲区中,然后使用该缓冲区返回一个迭代器:
import scala.collection.mutable
import scala.language.reflectiveCalls
case class Node(val subnodes: Seq[Node]) extends Iterable[Node] {
override def iterator: Iterator[Node] = {
val remaining = mutable.Queue.empty[Node]
Visitor.visit(this, item => iterator.remaining.enqueue(item))
remaining.iterator
}
}
// Same Visitor object
// Same Main object
这种解决方案的缺点是它引入了对 GC 施加压力的新分配,因为访问的元素的数量通常非常大。
您对如何从 迁移Traversable
到Iterable
使用现有访问者但不引入新分配有什么建议吗?