让我稍微扩展一下Rex Kerr 的answer。 Scala 的所有集合实际上有三个中心类,其中只有两个是集合的一部分。它们是Traversable、Iterable 和Iterator。
最基本的集合是Traversable。要成为Traversable,只有一个必要条件:它需要实现foreach 方法。因此,只要可以传递一个随后将应用于集合的每个元素的函数,它就可以是Traversable。例如:
class Three[A](a: A, b: A, c: A) extends Traversable[A] {
def foreach[U](f: (A) => U) {
f(a); f(b); f(c)
}
}
这将为您提供所有Traversable 方法,尽管map 和filter 等方法不会返回Three,而是返回Traversable。让它返回您定义的类要困难得多,而且许多专门的类都做不到。例如,Three 不能这样做,因为删除了一些元素的filter 的Three 是什么?
接下来是Iterator,它的作用与Traversable 几乎相同,但方式不同。 Iterator 必须定义两个方法:next 和 hasNext。例如:
class Three[A](a: A, b: A, c: A) extends Iterator[A] {
private var aReady, bIsRead, cIsRead = false
def hasNext = !(aIsRead && bIsRead && cIsRead)
def next = (aIsRead, bIsRead, cIsRead) match {
case (false, _, _) => aIsRead = true; a
case (_, false, _) => bIsRead = true; b
case (_, _, false) => cIsRead = true; c
case _ => Iterator.empty.next
}
}
这将给出Iterator 的所有方法,它们看起来与Traversable 中的方法大部分相同。方法之间的区别主要与Iterator只能使用一次有关。
最后是Iterable。要成为Iterable,一个类必须实现一个方法:iterator,它为该类返回一个Iterator。例如:
class Three[A](a: A, b: A, c: A) extends Iterable[A] {
// not necessary, but may offer a more efficient implementation
override def foreach[U](f: (A) => U) {
f(a); f(b); f(c)
}
def iterator = new Iterator[A] {
private var aReady, bIsRead, cIsRead = false
def hasNext = !(aIsRead && bIsRead && cIsRead)
def next = (aIsRead, bIsRead, cIsRead) match {
case (false, _, _) => aIsRead = true; a
case (_, false, _) => bIsRead = true; b
case (_, _, false) => cIsRead = true; c
case _ => Iterator.empty.next
}
}
}
所以,回到您的问题,您必须考虑您想要的预期行为是什么,以及您想要如何。特别是,Scala 集合中没有“向下”和“向左”的概念,这意味着 Node 可以有一个返回 Scala 集合的方法,但不能成为正确的说法,例如我们看到了 Rex Kerr 的解决方案。
编辑
让我举一个与 Rex Kerr 不同的例子。这里我做一个TraversableNode,遍历的顺序可以选择。
class Node[A] extends Traversable[A] {
var left: Node[A] = _
var down: Node[A] = _
var traverseLeft = true
var value: A = _
def foreach[U](f: (A) => U) = if (traverseLeft) foreachLeft(f) else foreachDown(f)
def foreachLeft[U](f: (A) => U) { f(value); if (left != null) left.foreachLeft(f) }
def foreachDown[U](f: (A) => U) { f(value); if (down != null) down.foreachDown(f) }
}
所以这个Node 是Traversable,它支持所有的Traversable 方法(尽管它仍然不会从map 等返回Node,等等——查找有关此的其他问题)。您可以使用标志 (traverseLeft) 选择它是向左还是向下遍历,所有正常的 Traversable 方法都将使用调用该方法的节点中设置的任何内容。
然而,这不是一个好的模型。我宁愿使用 Rex Kerr 的将迭代器返回到左和下的解决方案,或者完全离开 Scala 集合并使用Kiama 处理的东西。不过,后者是一个完全不同的范例,而不是你要硬塞进一个被音译为 Scala 的代码。