Scala map on iterator does not produce side effects

前端 未结 2 1216
情歌与酒
情歌与酒 2021-01-12 18:35

Why is it that,

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

does not print out

1
2
3
4
<
相关标签:
2条回答
  • The point of an Iterator is laziness. In other words, when you create an Iterator, it will not evaluate anything until you go to read the data. Here's what that looks like:

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

    Ok, we've got an iterator now. But it hasn't actually looked at the list yet.

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

    Now we have a new Iterator. This one will, when data is accessed, apply the function that has been mapped. But we still haven't actually looked at the original list.

    scala> mappedItr.next
    1
    

    This is the first time we have accessed data, so it is the first time that the Iterator has looked into the list. We called next, so we got the first element. Since our iterator has a map queued up, it applies the mapped function when we access that element. So we see the result of the function applied to the next item.

    We can do it again to get the next element:

    scala> mappedItr.next
    2
    

    And, again, it evaluates the function only when it needs to, in order to give us the final result.

    0 讨论(0)
  • 2021-01-12 19:14

    Cause map on iterator is lazy and you need some strictness:

    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((), (), (), ())
    

    When you doing foreach on iterator it is quite obvious that you're doing side effects, so lazyness will be undesired. I wouldn't said so about map.

    UPD

    As for your edit: the reason for such behaviour, is that there is implicit call of toString for statement result which in turn stricts the iterator -- try this code on your own:

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

    and you'll see that function f is never called

    0 讨论(0)
提交回复
热议问题