【问题标题】:Scala map on iterator does not produce side effects迭代器上的 Scala 映射不会产生副作用
【发布时间】:2012-09-19 20:27:56
【问题描述】:

为什么会这样,

scala> List(1,2,3,4).iterator.map((x: Int) => println(x))

不打印出来

1
2
3
4

同时

List(1,2,3,4).map((x: Int) => println(x))
List(1,2,3,4).foreach((x: Int) => println(x))
List(1,2,3,4).iterator.foreach((x: Int) => println(x))

都可以吗?

换句话说,为什么将类型 T 映射到 Unit 并且具有副作用的迭代器上的映射无法显示这些副作用?

编辑:

如果迭代器是惰性的,为什么下面的lazyMap调用实际上会从头到尾计算新的迭代器(提供完整的新迭代器)?

def lazyMap[T, U](coll: Iterable[T], f: T => U) = new Iterable[U] {
  def iterator = coll.iterator map f
}

scala> lazyMap(List(1,2,3,4), (x: Int) => x + 1)
res4: java.lang.Object with Iterable[Int] = (2, 3, 4, 5)

【问题讨论】:

  • 顺便说一句,您对Iterable的扩展是错误的(所有扩展Iterable的类都应该提供newBuilder方法)

标签: scala map iterator


【解决方案1】:

因为迭代器上的 map 是惰性的,你需要一些严格性:

scala> List(1,2,3,4).iterator.map((x: Int) => println(x))
res0: Iterator[Unit] = non-empty iterator

// nothing actually happened yet, just remember to do this printing things

scala> res0.toList
1
2
3
4
res1: List[Unit] = List((), (), (), ())

当你在迭代器上做 foreach 时,很明显你正在做副作用,所以懒惰是不受欢迎的。关于地图,我不会这么说。

UPD

至于您的编辑:这种行为的原因是对语句结果的 toString 隐式调用,这反过来又限制了迭代器——请自行尝试此代码:

scala> { lazyMap(List(1,2,3,4), {(x: Int) => println(x); x + 1}); 1 }

你会看到函数 f 永远不会被调用

【讨论】:

    【解决方案2】:

    迭代器的要点是懒惰。换句话说,当你创建一个迭代器时,它不会评估任何东西,直到你去读取数据。看起来是这样的:

    scala> val itr = List(1,2,3).iterator
    itr: Iterator[Int] = non-empty iterator
    

    好的,我们现在有了一个迭代器。但它还没有真正查看列表。

    scala> val mappedItr = itr.map((x: Int) => println(x))
    mappedItr: Iterator[Unit] = non-empty iterator
    

    现在我们有了一个新的迭代器。这将在访问数据时应用已映射的功能。但是我们仍然实际上并没有查看原始列表。

    scala> mappedItr.next
    1
    

    这是我们第一次访问数据,所以这是迭代器第一次查看列表。我们调用了next,所以我们得到了第一个元素。由于我们的迭代器有一个map 排队,所以当我们访问该元素时它会应用映射函数。所以我们看到了函数应用到next项目的结果。

    我们可以再做一次得到下一个元素:

    scala> mappedItr.next
    2
    

    同样,它仅在需要时评估函数,以便为我们提供最终结果。

    【讨论】:

      猜你喜欢
      • 2018-11-15
      • 1970-01-01
      • 2013-01-13
      • 2011-04-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-15
      相关资源
      最近更新 更多