Rust lets you assign and pass values, as Ruby does, but it adds compiler-checked rules about who owns each value and which parts of your program may access it at once. The practical distinction is simple: move a value when another binding should own it, borrow it when code needs temporary access, and use a mutable borrow only when exclusive access is available.
Start with the familiar: assignment in Ruby and Rust
In Ruby, assignment gives a variable a value, and variables can refer to objects. The Ruby documentation describes assignment and objects in Ruby’s own terms; those concepts are useful starting points, but they are not the same as Rust ownership or borrowing. See the Ruby 3.4 documentation for assignment and Object.
As an Amazon Associate I earn from qualifying purchases.
Rust makes ownership part of the language’s compile-time rules. Each value has one owner at a time. When that owner goes out of scope, Rust drops the value. This is how Rust makes cleanup predictable without relying on a garbage collector. The official Rust Book introduces these rules in Understanding Ownership.
What happens when a Rust value is assigned?
A heap-owning String moves
Consider this Rust code:
let s1 = String::from("hello");
let s2 = s1;
For a value such as String, assignment transfers ownership to s2. This is called a move. Afterward, s2 is the usable binding; trying to use s1 is rejected because it no longer owns the string. Rust has not made an automatic deep copy.
#1 Best Overall
If you really need a separate copy of the string data, request one explicitly with clone():
let s1 = String::from("hello");
let s2 = s1.clone();
Cloning can allocate and copy heap data, so use it when duplication is needed rather than as a default way to silence an ownership error. The official explanation of moves and cloning is in What Is Ownership?
Why the move matters
Because only one binding owns a value at a time, Rust can determine which scope is responsible for dropping it. A move changes that responsibility; it does not mean the value was copied or that both bindings now independently own it.
Rank #2
What borrowing lets a function do
A reference gives code access to a value without transferring ownership. The Rust Book puts it this way: “We call the action of creating a reference borrowing.”
For example, a function can read a borrowed string and return its length:
fn calculate_length(s: &String) -> usize {
s.len()
}
fn main() {
let word = String::from("hello");
let length = calculate_length(&word);
println!("{word} has {length} characters");
}
The function receives &String, not ownership of the String. The caller can therefore continue using word after the call. Borrowing avoids having to return the original value just so the caller can keep using it. The official chapter is References and Borrowing.
Rank #3
Immutable and mutable borrows
Use &T to read
An immutable reference, written &T, lets code inspect a value but does not authorize mutation through that reference. Several immutable references to the same value can be active at once: many readers may share access.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Use &mut T for exclusive mutation
A mutable reference, written &mut T, permits mutation. While that mutable borrow is active, Rust prevents other references to the same value from being used. Operationally, the rule is “many readers or one writer at a time.” For example:
fn add_exclamation(text: &mut String) {
text.push('!');
}
fn main() {
let mut greeting = String::from("hello");
add_exclamation(&mut greeting);
println!("{greeting}");
}
The binding must be declared mut to allow a mutable borrow. Rust tracks when a reference is last used, so a borrow can end before its surrounding lexical block ends; the rule is about overlapping use, not merely the braces around a variable.
How long must a reference remain valid?
A reference cannot outlive the value it refers to. Rust rejects a dangling reference—one that points to a value whose owner has already gone out of scope. As the Rust Book states, “References must always be valid.”
For example, a function cannot create a local String, return a reference to it, and let the string be dropped when the function exits. If a function needs to return data it created locally, returning an owned String is a straightforward option. Lifetimes describe how long references are valid; they do not make references owners of their data.
Should a function take ownership or borrow?
Choose the function parameter based on what the callee needs to do with the value:
- Pass ownership when the function should take responsibility for the value or consume it.
- Borrow with
&Twhen the function only needs to read the value temporarily. - Borrow with
&mut Twhen the function must mutate it and can have exclusive access during that borrow.
Also consider whether multiple parts of the program need simultaneous access and how long any reference must remain valid. These choices are the everyday way to apply Rust’s ownership rules rather than treat them as abstract memory-management theory.
Further reading
The official Rust Book page states that its current version assumes Rust 1.97.0 or later, released 2026-07-09, and uses edition = "2024" in Cargo.toml for Rust 2024 Edition idioms. The book is available in paperback and ebook formats from No Starch Press, according to its official landing page.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Free tools Windows power users keep installed
One-click scans. No signup required.




