M Logo
๐Ÿ“ Rust for Beginners ยท Part 7 of 22

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.

1. New project

Let's create a new project called ownership, and open it in VS Code.

bash
cargo new ownership
cd ownership

2. 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:

rust
fn main() {
    {
        let s = String::from("hello");
        println!("Inside: {s}");
    }
    println!("Outside: {s}");
}

Error:

text
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?

bash
cargo run

5. 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.

rust
fn main() {
    let s1 = String::from("hello");
    let s2 = s1;
    println!("s1 = {s1}, s2 = {s2}");
}

Error:

text
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.

bash
cargo run

8. 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.

rust
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.

bash
cargo run

12. Functions

Passing a value to a function also moves it. Here, print name takes ownership of name.

rust
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):

text
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 acceptable

13. Error

So after the call, we can't use name again. Same error: the value was moved.

bash
cargo run

14. Give back

One fix: the function gives the String back as its return value, and we store it again.

rust
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.

bash
cargo run

Recap

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.

ยฉ 2026 All Rights Reserved By Mahmudul Alam