Hi, I'm new to Rust, but an old hand with Haskell and C++. I am currently implementing the algorithms from the 'Iterators' chapter of Stepanov's "Elements of Programming" to see how well Rust copes with the kind of generic programming I want to do. I have two algorithms, and I am puzzled by the difference in behaviour. Here they are (note: this is using an iterator trait implemented like a C++ iterator, not the standard Rust one. At the moment I am interested in replicating the algorithms as they are, rather than implementing safe versions, and in any case I am interested in iterators with static safety guarantees, not runtime range checks).
pub fn for_each<I, P>(f : &I, l : &I, mut p : P) -> P
where I : Iterator + Readable, P : FnMut(&I::value_type) {
let mut i = (*f).clone();
while i != *l {
p(i.source());
i = i.successor();
}
p
}
pub fn reduce_nonempty<I, Op, F, D>(f : &I, l : &I, mut op : Op, mut fun : F) -> D
where I : Iterator + Readable, Op : FnMut(D, D) -> D, F : FnMut(&I) -> D {
let mut i = (*f).clone();
let mut r = fun(&i);
while i != *l {
r = op(r, fun(&i));
i = i.successor();
}
r
}
Note: both 'P' in the first, and 'F' in the second example are function traits that borrow their argument. Now I try and test both of these (I can post extra code if necessary, but I am trying to keep this to just the relevant bits):
let mut s : i64 = 0;
for_each(&f, &l, |&v| s += v);
assert_eq!(s, 6);
(aside: I wonder if I should be cloning 'v' here as '+=' takes ownership of the rhs?, is there a silent copy because the value is an integer? Is there any way to disable all silent copying, so that everything, even integers, have to be explicitly cloned? Otherwise I may get weird move errors when using generic functions with uncopyable objects)
Note: we have to borrow 'v' in the closure or we get a type mismatch (as expected). However with "reduce_nonempty" borrowing the argument produces an error and I have to write:
let r1 = reduce_nonempty(&f, &l, |a, b| a + b, |a| a.source().clone());
Alternatively this works:
let r1 = reduce_nonempty(&f, &l, |a, b| a + b, |&ref a| a.source().clone());
Why do the closures/function traits behave differently in these two examples?