scala - 将使用访问者的 Traversable 迁移到 Scala 2.13 中的 Iterable

标签 scala migration iterable visitor-pattern scala-2.13

migration guide to Scala 2.13说明 Traversable 已被删除,应该使用 Iterable 代替。对于一个项目来说,这个变化特别烦人,它使用访问者在树的 Node 类中实现 foreach 方法:

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 有什么建议吗?

最佳答案

如您所见,您需要扩展 Iterable 而不是 Traversable。你可以这样做:

case class Node(name: String, subnodes: Seq[Node]) extends Iterable[Node] {
  override def iterator: Iterator[Node] = Iterator(this) ++ subnodes.flatMap(_.iterator)
}

val a = Node("a", Seq())
val b = Node("b", Seq())
val c = Node("c", Seq(a, b))
val d = Node("d", Seq(c))

for (node@Node(name, _) <- d) {
  Console.println("Visiting node " + name + " with " + node.subnodes.length + " subnodes")
}

输出:

Visiting node d with 1 subnodes
Visiting node c with 2 subnodes
Visiting node a with 0 subnodes
Visiting node b with 0 subnodes

然后你可以做更多的操作比如:

d.count(_.subnodes.length > 1)

代码运行于 Scastie .

关于scala - 将使用访问者的 Traversable 迁移到 Scala 2.13 中的 Iterable,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65809358/

相关文章:

Scala:点到直线的正交投影

scala - 检查集合中包含的所有元组中给定的整数元素是否按连续顺序排列

git - 在 Git 分支中管理 Laravel 迁移

python - Python 的可迭代对象是否真的将所有值都存储在内存中?

java - 我如何必须返回 Iterator<E> 的 "next"方法?

scala - 如何在 Idea 模块中使用 gradle 设置 scala sdk?

scala - Spark : write Paquet from heterogeneous data

ruby-on-rails - heroku run rake db :migrate error “/usr/bin/env: ruby2.2: No such file or directory”

c# - Visual Studio 2010 项目转换为 Visual Studio 2012

python - “int”对象不可迭代