What does &mut mean in this case?

fn test() -> &'static str{
    let mut i: &str = "asdf";
    let remainder = &mut i;
    let another_ref_i = remainder;

    another_ref_i
}

fn main() {
    test();
}

another_ref_i here is a mutable reference to i (&mut &str), but if I do

fn test() -> &'static str{
    let mut i: &str = "asdf";
    let remainder = &mut i;
    let &mut another_ref_i = remainder;

    another_ref_i
}

fn main() {
    test();
}

another_ref_i becomes &str, why does &mut cancel the mutability of another_ref_i, help is really appreciated!

This is a destructuring pattern. It basically mean that you have something in the form &mut something and give the name another_ref_i to that something.

So, let’s first annotate all the types in the examples to avoid any potential confusion

fn test() -> &'static str{
    let mut i: &'static str = "asdf";
    let remainder: &mut &'static str = &mut i;
    let another_ref_i: &mut &'static str = remainder;

    another_ref_i
}
fn test() -> &'static str{
    let mut i: &'static str = "asdf";
    let remainder: &mut &'static str = &mut i;
    let &mut another_ref_i = remainder;
    // NOTE: another_ref_i: &'static str

    another_ref_i
}

Tjhe &mut in the let &mut another_ref_i line is a reference pattern. It’s functionality is to de-reference what it’s being matched against, or in other words to follow the pointer.

For example when you have something like

x: Option<&mut (i32, &mut bool)>

you can write something like

match x {
    Some(&mut (42, &mut true)) => /* ... */
    /* ... */
}

note that there are newer special rules in Rust, so-called ergonomics, that will actually make

match x {
    Some((42, true)) => /* ... */
    /* ... */
}

work as-well, thus &mut patterns can be kind-of uncommon nowadays.

In your particular example, a more ideomatic (and equivalent) way to write

let &mut another_ref_i = remainder;

would be

let another_ref_i = *remainder;

And actually, in case you’re wondering why the code without the &mut works as-well, we can talk about why this version

// NOTE: remainder: &mut &'static str
let another_ref_i: &'static str = remainder;

compiles as-well. The reason is that there’s an implicit (dereferencing) coercion happening here. The same is true for the return value in your first code example. The variable another_ref_i doesn’t have the right type to be returned from the function, but it can be coerced into the right type by dereferencing.

3 Likes

Patterns are the duals, or the "opposite", of expressions.

2 Likes

Thank you all for the help!

Is this supposed to be a link to something?

Yes, the Markdown parser didn't pick up the link without https:// for some reason. Fixed it, thanks for the heads up.