Reputation: 41
Checkout the Rust code below. It compiles
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(mut vec: Vec<i32>) -> Vec<i32> {
vec.push(22);
vec.push(44);
vec.push(66);
vec
}
Here I am declaring vec0
as immutable
but fill_vec
takes in a mutable vector. Depending on the function signature it seems Rust is changing the nature of the argument being passed.
My question is, this obviously seems like a "shot yourself in the foot" instant. Why does Rust allow this? Or, is this actually safe and I am missing something?
Upvotes: 3
Views: 583
Reputation: 30021
There are different things at play here that can all explain why this behavior make sense:
First of, mut
doesn't really mean "mutable". There are such things as interior mutability, Cell
s, Mutex
es, etc., which allow you to modify state without needing a single mut
. Rather, mut
means that you can get mutually exclusive references.
Second, mutability is a property of a binding. vec0
in main
and vec
in fill_vec
are different bindings, so they can have different mutability.
See also:
Finally ownership: fill_vec
takes full ownership of its parameter, which effectively doesn't exist anymore in main
. Why should the function not be allowed to do whatever it wants with its owned parameters? Had the function taken the parameter as a mutable reference, you would have needed to declare the original binding as mut
:
fn main() {
let mut vec0 = Vec::new();
// ^^^ now _needs_ a mutable binding
fill_vec(&mut vec0);
// ^^^^ needs an explicit `&mut` reference
}
fn fill_vec(vec: &mut Vec<i32>) {
// ^^^^ borrows rather than take ownership
// …
}
Upvotes: 4
Reputation: 2533
You're making the argument vec
of fill_vec
mutable. You are still passing the vec by value.
If you wanted a mutable reference you would have vec: &mut Vec<i32>
.
Upvotes: 0