Ownership and Borrowing
Ownership
- No garbage collector. Ownership instead.
- Each value in Rust has an owner.
- There can only be one owner at a time.
/// This example demonstrates the concept of ownership and move semantics in /// Rust. fn main() { // Strings have move semantics. // `s1` owns the string "hello". let s1 = String::from("hello"); // `s1` is MOVED into `s2`. // This is NOT a shallow copy. // `s2` now owns the string "hello". let s2 = s1; println!("{}, world!", s2); // Rust has invalidated `s1` because the String has been moved to `s2`. // ERROR: println!("{}, world!", s1); }
When the owner goes out of scope, the value will be dropped.
fn main() { // `s` is not valid here, it’s not yet declared. { // `s` is valid from this point forward. let s = String::from("hello"); println!("{}", s); } // this scope is now over, and `s` is no longer valid. // Rust calls `drop`. // ERROR println!("{}", s); // `s` is not valid here, it’s no longer in // scope. }
Rust will never automatically create deep copies of your data. Use std::clone::Clone
⮳.
/// This example demonstrates the use of the `clone` method to create a deep /// copy of a `String`. fn main() { // Create a String on the heap. let s1 = String::from("hello"); // Clone the String, creating a new String with the same content on the // heap. let s2 = s1.clone(); // `clone` deeply copies the heap data of the `String`, // not just the stack data. println!("{s2}"); }
If a type implements the std::marker::Copy
⮳ trait (stack-only, fixed-size values, like integers, floats, and tuples thereof), variables that use it do not move, but rather are trivially copied, making them still valid after assignment to another variable.
/// Integers implement the `Copy` trait, so they are copied instead of moved. fn main() { let x = 5; // x is an integer. let y = x; // y is a copy of x. // Both x and y are valid here. println!("x = {}, y = {}", x, y); }
Borrowing
Passing a variable to a function will move or copy, just as assignment does. To avoid passing a value along, borrow the value:
//! Demonstrates the concept of borrowing in Rust. fn main() { let s1 = String::from("hello"); let _len = calculate_length(&s1); // `&s1` passes an immutable reference to `s1` fn calculate_length(s: &str) -> usize { s.len() } // `s` goes out of scope here. Because the function does not have // ownership of what it refers to, `s1` is not dropped. println!("{s1}"); }
Mutable References
/// This function takes a mutable reference to a String and appends ", world" to /// it. fn change(some_string: &mut String) { some_string.push_str(", world"); // Modifies the string in place. println!("{some_string}"); } fn main() { let mut s = String::from("hello"); // Note the `mut` keyword. change(&mut s); }
If you have a mutable reference to a value, you can have no other simultaneous references to that value! Functions like a read/write lock.
Related Topics
- Lifetimes.
- Rust Patterns.