0

Why do I borrow twice in this example?

fn main() {
    let mut my_string = String::from("this is a string");
    let mut other_string_ref = &mut my_string; // first mutable reference 
    mut_ref(&mut my_string); 
    mut_ref(&mut other_string_ref); // invalid, because borrowed twice
}

// borrow happens when this function is called
fn mut_ref(s: &mut String) {
    print!("{}\n", s)
}

I know that you can only borrow once to avoid memory races. I also know that a variable goes out of scope when it is no longer used. Why does my_string not go out of scope after mut_ref(&mut my_string);. It is not used afterwards. We only use other_string_ref

User12547645
  • 6,955
  • 3
  • 38
  • 69
  • "borrow happens when this function is called" - a bit incorrect. The value is borrowed when you prepare arguments for a call. The function is not yet called at that moment. – Sergio Tulentsev Sep 28 '22 at 15:35
  • "Why does my_string not go out of scope" - it can't, because it's currently borrowed. – Sergio Tulentsev Sep 28 '22 at 15:36
  • 1
    Here's a version of your code without some unnecessary decorations: https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=3069a5ad26f7b2230d183a7e3464e93f hopefully in it, you can see better why this happens. – Sergio Tulentsev Sep 28 '22 at 15:38

2 Answers2

2

Your // invalid because borrowed twice comment is on the wrong line. It is the previous line where you try and borrow my_string again that causes the problem.

let mut other_string_ref = &mut my_string; creates a mutable (exclusive) reference to my_string. When you try and call mut_ref the first time you, you try and create a second mutable reference. This is not allowed as other_string_ref is still in scope.

my_string can't go out of scope because it is still referenced by other_string_ref.

See also:

Stargateur
  • 24,473
  • 8
  • 65
  • 91
Holloway
  • 6,412
  • 1
  • 26
  • 33
0

The main problem with your code is you (try to) have two mutable references and they are overlapping (active at the same time). This is not allowed. However, if you rewrite your code in a way so one of the references is fully processed before the other, it will work.

fn main() {
    let mut my_string = String::from("this is a string");
    mut_ref(&mut my_string); 
    
    let other_string_ref = &mut my_string;  
    mut_ref(other_string_ref);
}


fn mut_ref(s: &mut String) {
    print!("{}\n", s)
}
Sergio Tulentsev
  • 226,338
  • 43
  • 373
  • 367