【发布时间】:2020-09-01 21:02:54
【问题描述】:
我正在尝试链接Iterators:
var it = Iterator(1)
it.next
it = Iterator(2) ++ it
it.next
it.hasNext
这在hasNext 上无限循环,您可以在此处看到:https://scastie.scala-lang.org/qbHIVfsFSNO5OYmT4pkutA
如果你运行它并在堆栈无限循环时检查堆栈,它会在内容循环中循环:
at scala.collection.Iterator$ConcatIterator.merge(Iterator.scala:213)
at scala.collection.Iterator$ConcatIterator.advance(Iterator.scala:197)
at scala.collection.Iterator$ConcatIterator.hasNext(Iterator.scala:227)
(此堆栈来自 Scala 2.12.11,但 Scastie 链接在 2.13.2 中显示相同的行为)。
我知道在迭代器上调用方法后永远不应该使用它,但这似乎对我有用。使用var 指向“当前”迭代器并将其更改为指向一个新的迭代器,该迭代器附加前一个迭代器的其余部分。
以下轻微修改确实有效:
var it = Iterator(1)
it.next
val x = it
it = Iterator(2) ++ x
it.next
it.hasNext
Scastie 链接:https://scastie.scala-lang.org/1X0jslb8T3WIFLHamspYAg
这向我表明,以某种方式损坏的版本正在创建一个附加自身的迭代器。关于这里发生了什么的任何提示?
【问题讨论】:
-
总之,可变性不好。
-
这里没有异议。我正在将此与功能纯代码进行基准测试,如果可能的话,我会选择后者。唯一的问题是这是性能关键代码,因此如果它运行得非常快,它是一个合理的潜在突变候选者。令人惊讶的是,在 5 行命令式代码中会有多少混乱......
标签: scala mutability pass-by-name