I was wondering why Iterator::map takes a closure that has a value as argument instead of a reference, then I gave a look into the code and I found out that it's because Option::map (that is used internally) takes self instead of &self .
Anyway I cannot understand the reason of this choice. Why we want to move the value when we use map?
Generally speaking there is some guideline/good practice to decide when is better to prefer passing by reference or value?
If Option methods don't take self by value, then it's impossible to call any methods on the inner value that take self by value. Option provides an as_ref method to allow callers to choose not to consume the inner value instead, on an as-needed basis.
Your point makes sense, now I think I have understood. Thank you.
Anyway I was thinking that it is true since we want to avoid forcing that generic type derives the Copy trait, otherwise it would possible providing a reference. Let me explain better with the following example:
#[derive(Debug, Copy, Clone)]
// Useless enum... Just to prove my point
enum MyOption<T> where T: Copy {
Some(T),
}
#[derive(Debug, Copy, Clone)]
struct Foo(i32);
impl <T> MyOption<T> {
fn map(&self) -> T where T: Copy {
let option = *self;
match option {
MyOption::Some(x) => x,
}
}
}
fn main() {
let opt0 = MyOption::Some(5);
let val0 = opt0.map();
println!("{:?}", val0);
let opt1 = MyOption::Some(Foo(10));
let val1 = opt1.map();
println!("{:?}", val1);
}
So assuring that the generic type implements the Copy trait we could provide a map method that accepts &self instead of self.
I know that is a quite pointless observation, but I just want to understand better the language.
Iterator::map passing the value by value is the most flexible thing it can do (in increasing power for the closure: by shared reference &T, by mutable reference &mut T, by value T).
If passing by reference is necessary, the iterator you're calling map on will be yielding its elements behind an reference, e.g. if some_slice: &[T], then some_slice.iter() is an Iterator<Item = &T>, notIterator<Item = T>, so the closure passed to map takes arguments of type &T in this case.