I was doing the Rustlings challenges and stumbled upon some weird behavior while working on "move_semantics1.rs".
In main() the code moves the immutable value vec0 to fill_vec() which then mutates it anyway. Kindly explain to me: How is that legal? Why is that legal? Wouldn't this cause problems for library users who don't expect their values declared without mut to be mutated anyway?
pub fn main() {
let vec0 = Vec::new();
let mut vec1 = fill_vec(vec0);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
vec1.push(88);
println!("{} has length {} content `{:?}`", "vec1", vec1.len(), vec1);
}
fn fill_vec(vec: Vec<i32>) -> Vec<i32> {
let mut vec = vec;
vec.push(22);
vec.push(44);
vec.push(66);
vec
}
That's not a reference, it's passing the object by value, which transfers ownership. fill_vec is therefore allowed to do whatever it wants, it can return the original Vec or a completely new one.
You could do the same without the rebinding, just with fn fill_vec(mut vec: Vec<i32>) -> ..., the mut in the argument pattern is not part of the function's signature.
Yep. When you pass ownership into a function and back out like this, you get no guarantee that the variable won't change. In fact, it could even drop your vector and return a new vector with totally different values in it.
This is a useful pattern, but if you want to guarantee your value won't change, you would take the argument by reference using the & operator.
As a good exercise, try to look at vec0 after the call to fill_vec and see whether you can tell that it was mutated. It's legal because you gave away ownership, and the compiler prevents you from looking at it any more. Since you can't tell what happened to it, there's no need to restrict what the happens to it any more.