What is the impact of the return type in a function with a mutable borrow?

Viewed 129

The following code in Rust builds and runs:

fn func(s: &mut String) -> i32 {
    s.push_str("!");
    println!("{}", s);
    1
}

fn main() {
    let mut x = String::from("hello world");
    let v = func(&mut x);
    println!("{}", v);
    let r = &x[..];
    println!("{}", r);
}

If the return type of func is changed to &str, I get

error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
  --> src/main.rs:11:18
   |
9  |         let v = func(&mut x);
   |                           - mutable borrow occurs here
10 |         println!("{}", v);
11 |         let r = &x[..];
   |                  ^ immutable borrow occurs here
12 |         println!("{}", r);
13 |     }
   |     - mutable borrow ends here

I know that in a given scope, only one mutable reference is allowed, but how does the return type matter?

1 Answers

This question is basically a duplicate of Why doesn't the lifetime of a mutable borrow end when the function call is complete? but I already used and withdrew my gold badge dupe-hammer. Let me know when this has been closed as a dupe and I'll delete this answer.


If you don't return a reference, there can be no borrow.

If the return type of func is changed to &str

Then, due to lifetime elision, the function is equivalent to:

fn func<'a>(s: &'a mut String) -> &'a str

And the returned value is allowed to borrow from the argument. Thus you can no longer change the argument in case it invalidates the return value.

If the returned value didn't borrow from the argument, you can use lifetimes to disentangle them. Here we return a 'static string:

fn func(s: &mut String) -> &'static str {
    ""
}

See also:

Related