pla*_*pus 6 iterator scala map
为什么会这样,
scala> List(1,2,3,4).iterator.map((x: Int) => println(x))
Run Code Online (Sandbox Code Playgroud)
不打印出来
1
2
3
4
Run Code Online (Sandbox Code Playgroud)
而
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))
Run Code Online (Sandbox Code Playgroud)
都这样做?
换句话说,为什么迭代器上的地图将类型T映射到单位并且副作用无法显示这些副作用?
编辑:
另外,为什么如果迭代器是惰性的,下面的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)
Run Code Online (Sandbox Code Playgroud)
迭代器上的原因映射是懒惰的,你需要一些严格性:
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((), (), (), ())
Run Code Online (Sandbox Code Playgroud)
当你在迭代器上做foreach时很明显你正在做副作用,所以懒惰将是不受欢迎的.关于地图,我不会这么说.
UPD
至于你的编辑:这种行为的原因是,对于语句结果存在toString的隐式调用,而这反过来又会严格破坏迭代器 - 试试你自己的代码:
scala> { lazyMap(List(1,2,3,4), {(x: Int) => println(x); x + 1}); 1 }
Run Code Online (Sandbox Code Playgroud)
你会看到f永远不会调用该函数
迭代者的观点是懒惰.换句话说,当您创建迭代器时,在您去读取数据之前,它不会评估任何内容.这是看起来像:
scala> val itr = List(1,2,3).iterator
itr: Iterator[Int] = non-empty iterator
Run Code Online (Sandbox Code Playgroud)
好的,我们现在有了一个迭代器.但它还没有真正查看清单.
scala> val mappedItr = itr.map((x: Int) => println(x))
mappedItr: Iterator[Unit] = non-empty iterator
Run Code Online (Sandbox Code Playgroud)
现在我们有了一个新的Iterator.当访问数据时,这将应用已映射的函数.但我们还没有真正看过原来的清单.
scala> mappedItr.next
1
Run Code Online (Sandbox Code Playgroud)
这是我们第一次访问数据,因此这是Iterator第一次查看列表.我们打电话next,所以我们得到了第一个元素.由于我们的迭代器已经map排队,因此当我们访问该元素时它会应用映射函数.所以我们看到应用于next项目的函数的结果.
我们可以再做一次以获得下一个元素:
scala> mappedItr.next
2
Run Code Online (Sandbox Code Playgroud)
并且,它再次仅在需要时评估函数,以便给出最终结果.
| 归档时间: |
|
| 查看次数: |
2837 次 |
| 最近记录: |