2

(line <-lines) 如此具有破坏性,这让我感到非常惊讶!它完全展开线迭代器。因此,运行以下代码段将使 size = 0 :

  val lines = Source.fromFile(args(0)).getLines()
  var cnt = 0
  for (line <- lines) {
    cnt = readLines(line, cnt)
  }
  val size = lines.size

像这样隐藏的副作用是正常的 Scala 实践吗?

4

2 回答 2

5

Source.getLines()返回一个迭代器。对于每个迭代器,如果您调用诸如foreach上述或maptaketoList等的批量操作,则迭代器不再处于可用状态。那是Iterators的契约,更一般地说,继承 的类TraversableOnce

特别重要的是要注意,除非另有说明,否则在调用迭代器的方法后绝不应使用迭代器。两个最重要的例外也是唯一的抽象方法:next 和 hasNext。

对于继承的类,情况并非如此Traversable——对于那些您可以根据需要多次调用批量遍历操作的类。

于 2013-03-19T14:55:47.917 回答
3

Source.getLines()返回 an Iterator,并通过 anIterator将改变它。这在Scala 文档中非常清楚

迭代器是可变的:对它的大多数操作都会改变它的状态。虽然它通常用于遍历集合的元素,但它也可以在没有任何集合支持的情况下使用(参见伴随对象的构造函数)。

特别重要的是要注意,除非另有说明,否则在调用迭代器的方法后绝不应使用迭代器。两个最重要的例外也是唯一的抽象方法:next 和 hasNext。

使用for符号只是调用的语法糖mapflatMap以及foreach迭代器上的方法,它们再次有非常清晰的文档说明不使用迭代器:

重用:调用此方法后,应丢弃调用它的迭代器,只使用返回的迭代器。使用旧迭代器是未定义的,可能会发生变化,并且也可能导致对新迭代器的更改。

Scala 通常旨在成为一种“实用”语言——出于性能和互操作性的原因,允许突变和副作用,尽管不鼓励。然而,称其为“隐藏得很好”是有点牵强。

于 2013-03-19T14:56:11.767 回答