I'm a very beginner to Rust and I got confused by Rust functional programming style code. Assume freq is a vector containing non negative integers. The below code makes me confused.
Get the largest index with a positive value.
let key_max = (0..denom).rev().step_by(1).filter(|&i| freq[i] > 0).next().unwrap();
Get the number of positive values in freq.
let size = freq.iter().filter(|&&f| f > 0u32).count();
I wonder
why the first line of code use &i (a single &) while the second line of code uses &&f (double &).
In general, why do we need &&f in the second line of code? Why doesn't Rust make it simple to require only a single &?
Don't feel bad if you forget to put the &s, though, or put the wrong number of them. I certainly still get it wrong regularly. Getting compiler errors isn't a bad thing; it's totally ok to just write it without any then put them in where the compiler says they're needed
Thank you very much for your explanation! Would you help explain a little bit more why 0..denom creates an iterator of item type usize (without reference) while freq.iter() creates an iterator of item type &u32? Is it because freq is mutable? If I make freq non mutable, will freq.iter() creates an iterator of item type u32?
But why is it this way? Because of whether the items need to be available later. One can iterate a Vec with .iter() multiple times -- even simultaneously. So it gives out borrows, rather than the items themselves. If you want to consume the Vec as part of iterating -- meaning one couldn't get the values out of it again afterwards -- then you can use .into_iter() and it'll give you an owned T instead of the &T that .iter() gives you. (Of course, for something trivial like usizes, you can also do things like .iter().copied() to get an iterator that gives you usizes instead of &usizes without consuming the vector.)
Thank you very much for the explanation and information.
I had a try on an immutable vector myself. Both a single and double & works. Why is that? Does && has special meanings in this case? It somehow reminds of the universal reference in C++ (hasn't use C++ for many years).
It is because the Rem trait is implemented for both the combinations &i32 % i32 and i32 % i32, so you can compute modulo with both an integer and a reference to an integer.
Indeed in the first case, x has type &i32 and in the latter, x has type i32.
Thank you both very much on the good explanations. Now things make more sense to me!
Talking about modulus, I found Rust to be really peaky (comes with safety) about types. For example, Rust complains about apply % to different types of integers. To me, this is natural and should be supported and return the smaller type.
Won't go anywhere. Rust is deliberately picky about numeric types, because often, even when it feels natural, it hides footguns in the edge cases. If you support %, do you also support /? If so, what's 1000u64 / 2u8, and is it the same as 1000u64 % 2u8? These issues have been hashed over repeatedly, and the consensus is that it's better to encourage developers to be explicit about their numeric types, and to consider them carefully as part of application design.
% is different in that it is guaranteed that the resulting value is storable in the RHS type. That's not the case for any other arithmetic operation among integers.
I think it would be wiser to wait with submitting type-system-related proposals until you are well-acquainted with the type system.
Fortunately, no, not at all. Rust has nothing weird like the different kinds of C++ references, and && is not special. Rust "references" are much more like pointers, but with added type-level safety features, and thus, && is more like a pointer-to-pointer-to-T.
Again, it manifests in the argument of filter() because filter always passes a reference to the current item to the predicate closure, since it can't pass it by value. If the predicate yields true, then filter has to return the value of the current item, which wouldn't be possible if it transferred its ownership into the predicate.
And this is also one of the reasons that filter_map exists -- that way you get ownership of the thing in the closure, but you have to pass it back out of the closure again if you want to get it out of the iterator adapter.