Ownership, References, and Borrowing
https://doc.rust-lang.org/book/print.html#ownership-and-functions
Ownership rules
- Each value on the heap has a (variable) owner.
- Only one owner at a given time.
- The value is dropped (collected?) when the owner goes out of scope.
Here,
s2
is taking ownership of theString
thats1
points to, sos1
can no longer be used.let s1 = String::from("hello"); let s2 = s1; // Compile-time error if s1 is used here.
Here we’re only dealing with data on the stack, so no ownership rules apply:
let x = 5; let y = x;
Ownership is transferred during function calls too:
fn main() { let s = String::from("hello"); // s is no longer valid after this line; `takes_ownership` owns it now takes_ownership(s); }
Ownership can be transferred back to the caller via return value(s):
fn main() { let s = String::from("hello"); // s is no longer valid here, but s2 is. let s2 = takes_and_returns_ownership(s); }
This is too cumbersome to do everytime you want to use a value without necessarily owning it. What if we want to let a function use a value but not take ownership?
Rust fixes this with references.
fn main() { let s1 = String::from("hello"); // calculate_length gets a reference to s1, and so doesn't own s1. let len = calculate_length(&s1); println!("The length of '{}' is {}.", s1, len); } fn calculate_length(s: &String) -> usize { s.len() }
Having references as function parameters is called borrowing.
A function that accepts a reference can’t modify the data it refers to, unless it’s a mutable reference:
fn main() { let mut s = String::from("hello"); change(&mut s); } fn change(some_string: &mut String) { some_string.push_str(", world"); }
There are rules around mutable references, though, which allows Rust to avoid data races at compile time:
- You can have only one mutable reference to a particular piece of data in a particular scope.
- You cannot have a mutable reference while you have an immutable one (in a particular scope).
- Effectively, this is “either one mutable reference or many immutable references are allowed in a given scope”.
A reference’s scope starts from where it is introduced and continues through the last time that reference is used, so scopes are not necessarily denoted by
{}
.fn main() { let mut s = String::from("hello"); let r1 = &s; let r2 = &s; println!("{} and {}", r1, r2); // r1 and r2's scope _implicitly_ ends here // so this is fine let r3 = &mut s; println!("{}", r3); }