【问题标题】:How to program an iterator in scala without using a mutable variable?如何在不使用可变变量的情况下在 scala 中编写迭代器?
【发布时间】:2019-07-18 12:24:30
【问题描述】:

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

假设我有一个外部库,我通过调用函数 getNextElements(numOfElements: Int):Array[String] 来获取一些元素,并且我想使用该函数实现一个迭代器,但不使用指示“当前”数组的变量(在我的情况下,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)
}

【问题讨论】:

    标签: scala functional-programming iterator


    【解决方案1】:

    迭代器是可变的,至少没有返回状态变量的接口,所以一般来说,如果没有某种突变,你不能直接实现接口。

    话虽如此,Iterator 伴随对象中有一些非常有用的函数可以让您隐藏突变,并使实现更清晰。我会实现你的类似:

    Iterator.continually(getNextElements(10)).flatten
    

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

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

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

    【讨论】:

    • 其他替代方法是使用 Stream (或 LazyList 而不是 Iterator,第一个可以是纯的。
    • 我对迭代器接口一点也不熟悉。但是由于基于状态的循环和递归被证明在它们的表达能力上是等价的,我假设至少在理论上有可能只使用递归来实现它。如果我错了,请纠正我。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    • 2021-11-30
    相关资源
    最近更新 更多