Why does iter() require & for lambda functions, whereas range doesn't in this example

StackOverflow https://stackoverflow.com/questions/23440734

  •  14-07-2023
  •  | 
  •  

Question

I have some trouble understanding the differences in this example:

I thought that both range(..) and iter() are std::iter::Iterator So why can I pass |x| in the first example to map and filter, but have to pass it as |&x| in the 2nd example?

use std::iter::AdditiveIterator;

fn main() {
    let range1 = range(1,9);
    let range2 = [1,2,3,4,5,6,7,8,9];

    //indented for easier visualization
    let sum1 = range1       .map(| x| x * x).filter(| x| x % 2 == 0).sum();
    let sum2 = range2.iter().map(|&x| x * x).filter(|&x| x % 2 == 0).sum();

    println!("{}", sum1);
    println!("{}", sum2);
}
Was it helpful?

Solution

Just knowing they're both Iterator without knowing Iterators type parameter doesn't tell you anything about what they're iterating over, which is the important difference here. For this code:

  • range1 is an Iterator<int>
  • range2.iter() is an Iterator<&int>

That is, slice iterator returns references pointing directly into the slice (it has to do this or, for general T, it would be trying to steal ownership out of a borrowed slice &[T]: illegal), while range just returns the counter by-value since it constructs it internally, and is free to hand it out ("transferring ownership").

Hence, to get an int out of the slice iterator, you need to dereference the reference somehow, e.g. pattern matching through it via |&x| ..., or writing |x| *x * *x.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top