Scala:使用迭代器有什么兴趣?

时间:2016-06-14 12:24:17

标签: scala iterator

在Scala中与Regexes合作后我使用了Iterators,但我并不理解它的兴趣。
我知道它有一个状态,如果我在它上面调用next()方法,它每次都会输出不同的结果,但是我没有看到任何我可以用它做的事情,这是不可能的{{1 }}

它似乎不像Akka Streams那样工作(例如),因为下面的例子直接打印所有数字(没有等待我想象的一秒):

Iterable

那么使用lazy val a = Iterator({Thread.sleep(1000); 1}, {Thread.sleep(1000); 2}, {Thread.sleep(1000); 3}) while(a.hasNext){ println(a.next()) } 的目的是什么?

4 个答案:

答案 0 :(得分:5)

也许,迭代器最有用的属性是它们很懒惰。 考虑这样的事情:

   (1 to 10000)
     .map { x => x * x }
     .map { _.toString }
     .find { _ == "4" }

此代码段将10000个数字平方,然后生成10000个字符串,然后返回第二个字符串。 另一方面,这是:

   (1 to 10000)
     .iterator
     .map { x => x * x }
     .map { _.toString }
     .find { _ == "4" }

...只计算两个方块,并生成两个字符串。

当你需要包装一些设计不佳的(java?)对象以便能够以函数式处理它们时,迭代器也常常很有用:

val rs: ResultSet = jdbcQuery.executeQuery()
new Iterator { 
   def next = rs
   def hasNext = rs.next
}.map { rs =>
   fetchData(rs)
}

Streams类似于迭代器 - 它们也很懒惰,也可用于包装:

Stream.continually(rs).takeWhile { _.next }.map(fetchData)

但主要区别在于流记住了实现的数据,因此您可以多次遍历它们。这很方便,但如果原始数据量非常大,可能会很昂贵,特别是如果它被过滤到更小的尺寸:

Source
  .fromFile("huge_file.txt")
  .getLines 
  .filter(_ == "")
  .toList

这仅大致(忽略缓冲,对象开销和其他特定于实现的细节),内存量,将一行保留在内存中,加上文件中有许多空行。

另一方面:

val reader = new FileReader("huge_file.txt")
Stream
  .continually(reader.readLine)
  .takeWhile(_ != null)
  .filter(_ == "")
  .toList

...将以内存中huge_file.txt整个内容结束。

最后,如果我正确理解了你的例子的意图,那么你可以用迭代器来实现它:

val iterator = Seq(1,2,3).iterator.map { n => Thread.sleep(1000); n }
iterator.foreach(println)
// Or while(iterator.hasNext) { println(iterator.next) } as you had it.

答案 1 :(得分:1)

对迭代器http://www.scala-lang.org/docu/files/collections-api/collections_43.html

有一个很好的解释
  

迭代器不是一个集合,而是一种访问它的方法   集合的元素一个接一个。关于的两个基本操作   迭代器是下一个和hasNext。对it.next()的调用将返回   迭代器的下一个元素并提升迭代器的状态。   然后在同一个迭代器上再次调用将生成元素   一个超出之前返回的一个。如果没有更多的元素   要返回,对next的调用将抛出NoSuchElementException。

答案 2 :(得分:1)

首先,您应该了解您的示例有什么问题:

  

lazy val a = Iterator({Thread.sleep(1); 1},{Thread.sleep(1); 2},   {了Thread.sleep(2); 3})while(a.hasNext){println(a.next())}

如果查看Iterator的应用方法,您会看到没有按姓名调用,因此Thread.sleep方法同时调用apply Thread.sleep调用。此外,sleep以毫秒为单位获取睡眠时间参数,因此如果您想在一秒内Thread.sleep(1000)线程,则应通过val a = Iterator.iterate(1)(x => {Thread.sleep(1000); x+1}) 。 伴随对象具有允许您执行下一步的其他方法:

Iterator
当您需要处理大数据时,

val it = new Iterator[Int] { var i = -1 def hasNext = true def next(): Int = { i += 1; i } } 非常有用。您也可以实现自己的:

{{1}}

答案 3 :(得分:0)

  

我没有看到任何我可以用它做的事情,这是不可能的Iterable

事实上,大多数收藏品也可以用Array完成,但我们不这样做,因为它不太方便

同样的理由适用于迭代器,如果你想建模一个可变状态,那么迭代器更有意义。

例如,Random的实现方式类似于迭代器,因为它的用例更适合迭代器,而不是迭代。