In this article, you will learn how ownership and borrowing works, and what they are in Rust.
Prerequisites
To follow through this article, you need to have at least a basic knowledge of Rust, and you need the Rust compiler installed in your system.
What is ownership
Ownership is a set of rules that regulates memory usage in rust programs. These rules are key to rust’s memory safety, despite the lack of a garbage collector. Ownership provides a way for the Rust compiler to track all allocated memory at compile time.
The following are the rules governing ownership:
- Each value must have only one owner at any time: that means that if you attempt to store an owner in another one the previous one passes its value to the new owner and loses its value.
- An owner can only exist in one scope: that means if you pass an owner to a function, the owner leaves its current scope and moves to the new function’s scope. The example below shows
name
being moved frommain
’s scope togreet
’s scope:
fn main() {
let name = "John".to_string();
greet(name);
println!("Name: {}", name); // <- throws an error because it is out of scope
}
fn greet(name: String) {
println!("Hello, {}", name);
}
Owners in Rust are similar to variables or constants in other programming languages.
Borrowing and References
Borrowing allows functions to reference owners from a scope without moving them to the new function’s scope. To borrow an owner, you first need to get a reference to it. To get the reference, you need the & operator:
fn main() {
let name = "John".to_string();
greet(&name);
println!("Name: {}", name);
}
fn greet(name: &String) {
println!("Hello, {}", name);
}
Borrowing the owner in a function lets you use its value without necessarily moving the owner to the new function’s scope.
Mutable References
My default, Rust doesn’t let you modify the value of a borrowed owner. For example, the following code won’t compile:
fn main() {
let mut greeting = "Hello, ".to_string();
add_name(&greeting);
println!("{}!", greeting);
}
fn add_name(greeting: &String) {
greeting.push_str("John");
}
To make the above example work, you need to retrieve a mutable reference to the owner:
fn main() {
let mut greeting = "Hello, ".to_string();
add_name(&mut greeting);
println!("{}!", greeting);
}
fn add_name(greeting: &mut String) {
greeting.push_str("John");
}
To specify a mutable reference to an owner prefix the owner name with &mut
. Like in the 3rd line in the code above. A mutable reference allows a function to borrow and mutate an owner.
Conclusion
This article focuses on how ownership and borrowing works, and how to use them. I’ve compiled some links that can help you with any further research you may want to make:
Top comments (2)
I wish they had called it lending.
Exactly!!
Like "it's still mine, but you can use it"