Ownership

Rust's unique memory management model - the ownership system.

Intermediate⏱️ 35 min📚 Prerequisites: 1

Ownership

Ownership is one of Rust's most important and unique features. This system guarantees memory safety without using a garbage collector.

Principles

  1. Every value has one "owner"
  2. There can only be one owner at a time
  3. When the owner goes out of scope, the value is freed

Scope and Ownership

RUST
{  // s doesn't exist here
    let s = String::from("hello");  // s is valid from here
    // use s
}  // s goes out of scope, memory is freed

Move Semantics

RUST
let s1 = String::from("hello");
let s2 = s1;  // s1's value moves to s2
// s1 is no longer usable!
println!("{}", s1);  // ERROR!

Copy Types

Some types are automatically copied (Copy trait):

RUST
let x = 5;
let y = x;  // x's value is copied, not moved
println!("{}", x);  // OK, x is still usable

Copy types: integers, bool, char, tuples (if all elements are Copy).

Code Examples

Scope and Ownership

How ownership works in scopes

RUST
fn main() {
    let s = String::from("hello");
    println!("s value: {}", s);
    {
        let inner = String::from("world");
        println!("inner value: {}", inner);
    }
    println!("s is still valid: {}", s);
}

Explanation:

Variable lifetimes are tied to scope. When a variable goes out of scope, memory is automatically freed.

Move Semantics

How the move operation works

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

Explanation:

The String type is not Copy, so when we assign s1 to s2, the value "moves". s1 is no longer usable after this.

Copy Types

Automatic copying of Copy types

RUST
fn main() {
    let x = 5;
    let y = x;
    println!("x: {}", x);
    println!("y: {}", y);
    let tup = (1, 2, 3);
    let tup2 = tup;
    println!("tup: {:?}", tup);
}

Explanation:

Integers and other Copy types are automatically copied, not moved. Both variables remain usable.

Blockchain: Ownership of Transactions

Understanding ownership in blockchain transactions

RUST
struct Transaction {
    from: String,
    to: String,
    amount: u64,
}
fn process_transaction(tx: Transaction) {
    println!("Processing: {} -> {} ({} tokens)", tx.from, tx.to, tx.amount);
}
fn main() {
    let tx = Transaction {
        from: String::from("0xAlice"),
        to: String::from("0xBob"),
        amount: 100,
    };
    process_transaction(tx);
}

Explanation:

In blockchain, transactions should be consumed when processed. Rust's ownership system enforces this - once a transaction is moved, it can't be used again, preventing accidental double-processing.

Exercises

Ownership Practice

Create a String, assign it to another variable, and try to use the original!

Medium

Starter Code:

RUST
fn main() {
    let text = String::from("Rust");
}