如何在不使用可变变量的情况下在Scala中对迭代器进行编程?

时间:2019-07-18 12:24:30

标签: scala functional-programming iterator

我想以功能方式实现迭代器特征,即不使用var。该怎么做?

假设我有一个外部库,可以在其中通过调用函数getNextElements(numOfElements: Int):Array[String]得到一些元素,并且我想使用该函数实现一个Iterator,但不使用表示“当前”数组的变量(在我的情况下, var缓冲区)。我该如何以功能性方式实现呢?

class MyIterator[T](fillBuffer: Int => Array[T]) extends Iterator[T] {
    var buffer: List[T] = fillBuffer(10).toList

    override def hasNext(): Boolean = {
        if (buffer.isEmpty) buffer = fillBuffer(10).toList
        buffer.nonEmpty
    }

    override def next(): T = {
        if (!hasNext()) throw new NoSuchElementException()

        val elem: T = buffer.head
        buffer = buffer.tail
        elem
    }
}

class Main extends App {
    def getNextElements(num: Int): Array[String] = ???

    val iterator = new MyIterator[String](getNextElements)

    iterator.foreach(println)
}

1 个答案:

答案 0 :(得分:4)

迭代器是可变的,至少在没有返回状态变量的接口的情况下是可变的,因此,一般来说,如果没有某种形式的突变,就不能直接实现接口。

话虽这么说,Iterator伴随对象中有一些非常有用的函数,这些函数可让您隐藏突变并简化实现。我会像这样实现您的:

Iterator.continually(getNextElements(10)).flatten

这在需要填充缓冲区时调用getNextElements(10)flatten将其从Iterator[Array[A]]更改为Iterator[A]

请注意,这将返回一个无限迭代器。您的问题没有说明检测源元素的结尾,但是我通常会使用takeWhile来实现。例如,如果getNextElements在没有更多元素时返回空数组,则可以执行以下操作:

 Iterator.continually(getNextElements(10)).takeWhile(!_.isEmpty).flatten