Can't reassign a mutable argument

fn main() {
    {
        let mut s = String::from("abc");
        example(&mut s);
    }
}

fn example(mut s1: &mut String) {
    let mut s2 = String::from("abc");
    s1 = &mut s2; // error: `s2` does not live long enough

    dbg!(&s1);
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
warning: value passed to `s1` is never read
 --> src/main.rs:8:16
  |
8 | fn example(mut s1: &mut String) {
  |                ^^
  |
  = help: maybe it is overwritten before being read?
  = note: `#[warn(unused_assignments)]` on by default

error[E0597]: `s2` does not live long enough
  --> src/main.rs:10:10
   |
8  | fn example(mut s1: &mut String) {
   |                    - let's call the lifetime of this reference `'1`
9  |     let mut s2 = String::from("abc");
10 |     s1 = &mut s2; // error: `s2` does not live long enough
   |     -----^^^^^^^
   |     |    |
   |     |    borrowed value does not live long enough
   |     assignment requires that `s2` is borrowed for `'1`
...
13 | }
   | - `s2` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.
warning: `playground` (bin "playground") generated 1 warning
error: could not compile `playground` due to previous error; 1 warning emitted

If I inline the function like this:

    let mut s = String::from("abc");
    {
        let mut s1: &mut String = &mut s;
        let mut s2 = String::from("abc");
        s1 = &mut s2; // no error here

        dbg!(&s1);
    };

Obviously, I receive no error.

In your first example, s2 is created within the function body, so it only lives within that function's scope.

In your second example, both s1 and s2 are created within the same scope, hence you don't see any errors.

Here, s1 is of type &'a mut String, where lifetime 'a must be longer than the function runs.

Here, s1 is of type &'b mut String, where 'b lasts at least until after the line where dbg!(&s1) appears, but at most until the end of the block (which is the same position in your example). When you write &mut s2, the lifetime of that expression can be made to match the lifetime of s1.

1 Like

You can fix it as follows:

 fn example(mut s1: &mut String) {
+    let mut s1 = s1;
     let mut s2 = String::from("abc");
     s1 = &mut s2; // error: `s2` does not live long enough

     dbg!(&s1);
 }

(Playground)

Edit: But that's probably maybe not what you want, see @kpreid's post below.

If you are trying to change what the mutable reference points to (sometimes called an "out parameter" of the function), then the code you want is *s1 = s2; instead of s1 = &mut s2;.

3 Likes

I'm not trying to pass s2 ownership to *s1, if that is what you are saying.

Well… we can not read minds and your code does that. Tries to do, at least.

1 Like

I think I understand my mistake now. I was under the impression that s1 was part of example scope.
But this not the case.
A more correct inline conversion for example is probably this:

    let mut s = String::from("abc");
    {
        let mut s1: &mut String = &mut s;
        {
            let mut s2 = String::from("abc");
            s1 = &mut s2;

            dbg!(&s1);
        };
        dbg!(&s1);
    }

I'm I right?

The binding s1 is within the function scope. However, the value stored in that variable (and thus the type of s1, which is &'a mut String) has a lifetime 'a that may go beyond the function scope.

This may become more obvious when you desugar the function:

fn example<'a>(mut s1: &'a mut String) {
    let mut s2 = String::from("abc");
    s1 = &mut s2; // error: `s2` does not live long enough

    dbg!(&s1);
}

(Playground)

Here 'a is a lifetime that comes from outside the function and is usually inferred by the compiler.

P.S.: I still struggle a bit to use the proper wording ("binding", "scope", etc.) correctly. I hope I have not mixed them up.

Ok, so the inferred 'a lifetime is still tied to s1 even if I declared it as mut. Are there any useful examples for declaring a function argument of type &Something or &mut Something as a mutable bidding?

You often see that pattern when subslicing into a slice repeatedly in a loop. For a trivial example, this function strips all instances of [1] and [2, 3] off the start of its input slice, returning a subslice:

pub fn strip_prefix<'a>(mut slice: &'a [i32]) -> &'a [i32] {
    loop {
        match slice {
            [1, rest @ ..] => slice = rest,
            [2, 3, rest @ ..] => slice = rest,
            _ => return slice,
        }
    }
}

I often use this kind of pattern for iteratively encoding and decoding different kinds of escaped strings.

2 Likes

@jbe, @LegionMammal978 , @kpreid

Thank you all for your help.