Rust Ownership Explained: Move, Clone and Scope
November 10, 2026
Welcome to episode 7 of Rust for Beginners, a series for complete beginners (no programming experience needed). In the last video, we learned about loops. Today, we'll learn ownership. It's the most important idea in Rust, and the reason Rust is safe without a garbage collector. Every code block below is the exact code from the video, ready to copy.
- All episodes are in the Rust Tutorial for Beginners playlist.
- Versions used: Rust 1.99.1 on Ubuntu, VS Code with rust-analyzer.
1. New project
Let's create a new project called ownership, and open it in VS Code.
cargo new ownership
cd ownership2. Three rules
Ownership has three rules. Each value has one owner. There can only be one owner at a time. And when the owner goes out of scope, the value is dropped.
3. Scope
A scope is a block in curly braces. Inside this block, we create a String called s. It lives until the closing brace.
src/main.rs:
fn main() {
{
let s = String::from("hello");
println!("Inside: {s}");
}
println!("Outside: {s}");
}Error:
error[E0425]: cannot find value `s` in this scope
--> src/main.rs:6:25
|
6 | println!("Outside: {s}");
| ^
|
help: the binding `s` is available in a different scope in the same function
--> src/main.rs:3:13
|
3 | let s = String::from("hello");
| ^4. Out of scope
What if we use s after the block?
cargo run5. Error
Rust can't find s. When the block ended, s went out of scope, and its memory was freed automatically.
6. Move
Now, a String in one variable, s one. We write let s two equals s one.
fn main() {
let s1 = String::from("hello");
let s2 = s1;
println!("s1 = {s1}, s2 = {s2}");
}Error:
error[E0382]: borrow of moved value: `s1`
--> src/main.rs:4:21
|
2 | let s1 = String::from("hello");
| -- move occurs because `s1` has type `String`, which does not implement the `Copy` trait
3 | let s2 = s1;
| -- value moved here
4 | println!("s1 = {s1}, s2 = {s2}");
| ^^ value borrowed here after move
|
help: consider cloning the value if the performance cost is acceptable
|
3 | let s2 = s1.clone();
| ++++++++7. Error
Let's run it. Rust says: borrow of moved value. The String was moved into s two. s one is no longer valid, so we can't use it.
cargo run8. Why
Why? If both owned the same text, both would try to free it at the end. Moving the ownership prevents that.
9. Copy
Simple values like integers are different. They are copied, so x and y both stay valid.
fn main() {
let x = 5;
let y = x;
println!("x = {x}, y = {y}");
let s1 = String::from("hello");
let s2 = s1.clone();
println!("s1 = {s1}, s2 = {s2}");
}Output: x = 5, y = 5 / s1 = hello, s2 = hello
10. Clone
And if we really want a second String, we call clone. That makes a full, separate copy. The compiler even suggested this.
11. Run C
Let's run it. Both pairs work.
cargo run12. Functions
Passing a value to a function also moves it. Here, print name takes ownership of name.
fn main() {
let name = String::from("Rust");
print_name(name);
println!("Again: {name}");
}
fn print_name(text: String) {
println!("Name: {text}");
}Error (verified in the VM, shortened):
error[E0382]: borrow of moved value: `name`
--> src/main.rs:4:23
|
2 | let name = String::from("Rust");
| ---- move occurs because `name` has type `String`, which does not implement the `Copy` trait
3 | print_name(name);
| ---- value moved here
4 | println!("Again: {name}");
| ^^^^ value borrowed here after move
|
note: consider changing this parameter type in function `print_name` to borrow instead if owning the value isn't necessary
...
help: consider cloning the value if the performance cost is acceptable13. Error
So after the call, we can't use name again. Same error: the value was moved.
cargo run14. Give back
One fix: the function gives the String back as its return value, and we store it again.
fn main() {
let name = String::from("Rust");
let name = print_name(name);
println!("Again: {name}");
}
fn print_name(text: String) -> String {
println!("Name: {text}");
text
}Output: Name: Rust / Again: Rust
15. Run E
Let's run it. It works, but it's clumsy. In the next video, we'll see a much better way.
cargo runRecap
To recap: every value has one owner. When the owner goes out of scope, the value is dropped. Assigning or passing a String moves it. Integers are copied. And clone makes a deep copy.