【问题标题】:Why `Source.fromFile(...).getLines()` is empty after I've iterated over it?为什么`Source.fromFile(...).getLines()`在我迭代之后是空的?
【发布时间】:2013-03-08 07:35:42
【问题描述】:

(行

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

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

【问题讨论】:

标签: scala side-effects


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    Source.getLines() 返回一个Iterator,通过Iterator 会改变它。这在Scala documentation 中已经很清楚了

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

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

    使用for 表示法只是在迭代器上调用mapflatMapforeach 方法的语法糖,它们再次有非常明确的文档说明不要使用迭代器:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-31
      • 2019-11-10
      • 2021-12-18
      • 1970-01-01
      • 2011-04-17
      • 1970-01-01
      • 2018-05-24
      • 1970-01-01
      相关资源
      最近更新 更多