让迭代器it逐个返回所有元素最简单的方法是使用while循环:

    Scala为Traversable, Iterable和Seq类中的迭代器提供了许多类似的方法。比如:这些类提供了foreach方法以便在迭代器返回的每个元素上执行指定的程序。使用foreach方法可以将上面的循环缩写为:

    与往常一样,for表达式可以作为foreach、map、withFilter和flatMap表达式的替代语法,所以另一种打印出迭代器返回的所有元素的方式会是这样:

    1. for (elem <- it) println(elem)

    在迭代器或traversable容器中调用foreach方法的最大区别是:当在迭代器中完成调用foreach方法后会将迭代器保留在最后一个元素的位置。所以在这个迭代器上再次调用next方法时会抛出NoSuchElementException异常。与此不同的是,当在容器中调用foreach方法后,容器中的元素数量不会变化(除非被传递进来的函数删除了元素,但不赞成这样做,因为这会导致意想不到的结果)。

    迭代器的其他操作跟Traversable一样具有相同的特性。例如:迭代器提供了map方法,该方法会返回一个新的迭代器:

    另一个例子是关于dropWhile方法,它用来在迭代器中找到第一个具有某些属性的元素。比如:在上文所说的迭代器中找到第一个具有两个以上字符的单词,你可以这样写:

    1. scala> val it = Iterator("a", "number", "of", "words")
    2. it: Iterator[java.lang.String] = non-empty iterator
    3. scala> it dropWhile (_.length < 2)
    4. res4: Iterator[java.lang.String] = non-empty iterator
    5. res5: java.lang.String = number

    再次注意it在调用dropWhile方法后发生的变化:现在it指向了list中的第二个单词”number”。实际上,it和dropWhile返回的结果res4将会返回相同的元素序列。

    只有一个标准操作允许重用同一个迭代器:

    这个操作返回两个迭代器,每个都相当于迭代器it的完全拷贝。这两个iterator相互独立;一个发生变化不会影响到另外一个。相比之下,原来的迭代器it则被指定到元素的末端而无法再次使用。

    总的来说,如果调用完迭代器的方法后就不再访问它,那么迭代器的行为方式与容器是比较相像的。Scala容器库中的抽象类TraversableOnce使这一特质更加明显,它是 Traversable 和 Iterator 的公共父类。顾名思义,TraversableOnce 对象可以用foreach来遍历,但是没有指定该对象遍历之后的状态。如果TraversableOnce对象是一个迭代器,它遍历之后会位于最后一个元素,但如果是Traversable则不会发生变化。TraversableOnce的一个通常用法是作为一个方法的参数类型,传递的参数既可以是迭代器,也可以是traversable。Traversable类中的追加方法++就是一个例子。它有一个TraversableOnce 类型的参数,所以你要追加的元素既可以来自于迭代器也可以来自于traversable容器。

    带缓冲的迭代器

    有时候你可能需要一个支持“预览”功能的迭代器,这样我们既可以看到下一个待返回的元素,又不会令迭代器跨过这个元素。比如有这样一个任务,把迭代器所指元素中的非空元素转化成字符串。你可能会这样写:

    但仔细看看这段代码,就会发现明显的错误:代码确实会跳过空字符串,但同时它也跳过了第一个非空字符串!

    要解决这个问题,可以使用带缓冲能力的迭代器。[BufferedIterator]类是[Iterator]的子类,提供了一个附加的方法,head。在BufferedIterator中调用head 会返回它指向的第一个元素,但是不会令迭代器步进。使用BufferedIterator,跳过空字符串的方法可以写成下面这样:

    1. def skipEmptyWords(it: BufferedIterator[String]) =
    2. while (it.head.isEmpty) { it.next() }

    通过调用buffered方法,所有迭代器都可以转换成BufferedIterator。参见下例:

    1. scala> val it = Iterator(1, 2, 3, 4)
    2. it: Iterator[Int] = non-empty iterator
    3. scala> val bit = it.buffered
    4. BufferedIterator[Int] = non-empty iterator
    5. res10: Int = 1
    6. scala> bit.next()
    7. res11: Int = 1
    8. scala> bit.next()
    9. res11: Int = 2

    注意,调用BufferedIterator bit的head方法不会令它步进。因此接下来的bit.next()返回的元素跟相同。