fn say_hello(s: &str) {
println!("Hello {}", s);
}
Why does this work
fn main() {
let mut name = String::from("Charlie");
let x = &mut name;
say_hello(x);
name.push_str(" Brown");
}
but this doesn't?
fn main() {
let mut name = String::from("Charlie");
let x = &mut name;
name.push_str(" Brown");
say_hello(x);
}
all I did was switch the order of the two functions but it seems like x
has mutably borrowed name and push_str has also mutably borrowed name in both situations, so why does the first example compile?
If I take out the call to say_hello()
why does the order of the two not matter even though there are still two mutable borrows?
Edit: Is this similar?
fn change_string(s: &mut String) { // s is mutably borrowed but isn't used yet
println!("{}", s.is_empty()); // so the scopes don't overlap even though is_empty is making an immutable borrow?
s.push_str(" Brown");
}
It is very inconvenient to pass the ownership of a variable to another function and then return the ownership. Rust supports a concept, borrowing, where the ownership of a value is transferred temporarily to an entity and then returned to the original owner entity.
A reference is like a pointer in that it's an address we can follow to access the data stored at that address; that data is owned by some other variable. Unlike a pointer, a reference is guaranteed to point to a valid value of a particular type for the life of that reference.
One of Rust's borrowing rules is that mutable references are exclusive. Meaning, while x
is alive, name
cannot be used.
So, why does the first example compile even if x
is still in scope? Because Rust also has non-lexical lifetimes meaning x
stops "living" after its last use.
fn main() {
let mut name = String::from("Charlie");
let x = &mut name;
say_hello(x); // "x"s lifetime ends here, releasing the exclusive borrow
name.push_str(" Brown"); // "name" can be used again
}
Because in your first case, the two mutable borrow scopes don't overlap and you have only one borrow at any given point of time; but in your second case, they overlap, which means you have multiple mutable borrows at the certain point of time, which is not allowed:
First case:
fn main() {
let mut name = String::from("Charlie");
let x = &mut name;
say_hello(x); // the mutable borrow ends here
name.push_str(" Brown"); // a new mutable borrow
}
Second case:
fn main() {
let mut name = String::from("Charlie");
let x = &mut name;
name.push_str(" Brown"); // the first mutable borrow is still
// alive, you have two mutable borrows here
say_hello(x); // the first mutable borrow ends here
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With