Rajarshi Maitra
Rajarshi Maitra

Reputation: 41

Immutable object changing to mutable depending on function signature

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

Answers (2)

mcarton
mcarton

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, Cells, Mutexes, 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

ShadowMitia
ShadowMitia

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

Related Questions