Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Lesson 1 — Mastering Ownership & Borrowing


🎯 Learning Objectives

  • Hiểu cơ chế ownershipborrowing — cốt lõi ngăn chặn data race trong Rust.

🔑 Key Concepts & Glossary

Ownership

Mỗi giá trị trong Rust chỉ có một owner duy nhất tại một thời điểm. Khi owner bị drop, giá trị bị giải phóng. Thay vì garbage collector, compiler kiểm tra ownership/borrowing tại compile time.

Borrowing Rules

  • &T (Immutable Borrow): nhiều tham chiếu chỉ đọc có thể tồn tại đồng thời.
  • &mut T (Mutable Borrow): chỉ được một tham chiếu ghi tại một thời điểm.

Borrowing Conflict

Nếu bạn cố vừa giữ &mut& cùng lúc, compiler báo lỗi để tránh data race (trong single-thread) hoặc UB (undefined behavior).

Các thuật ngữ quan trọng:

  • Ownership: cơ chế bảo đảm mỗi giá trị chỉ có một chủ sở hữu; tự động giải phóng khi rời scope.
  • Borrowing: mượn tham chiếu đến dữ liệu mà không chuyển quyền sở hữu (&T hoặc &mut T).
  • Immutable Borrow (&T): tham chiếu chỉ đọc, có thể tồn tại nhiều cái song song.
  • Mutable Borrow (&mut T): tham chiếu cho phép chỉnh sửa, chỉ duy nhất một cái tồn tại.
  • Data Race: xảy ra khi (i) có ít nhất một ghi, (ii) không đồng bộ hóa, (iii) truy cập đồng thời trên cùng vùng nhớ. → Hậu quả: kết quả không xác định, dễ gây crash hoặc lỗi bảo mật. Rust ngăn chặn điều này ở compile time.

💻 Example Implementation

Cargo.toml

[package]
name = "lesson01_ownership"
version = "0.1.0"
edition = "2024"

src/main.rs


fn main() {
    let mut s = String::from("Hi, dp");

    // Immutable borrow
    let len = calculate_length(&s);
    println!("Length = {}", len);

    // Mutable borrow
    change(&mut s);
    println!("After change = {}", s);

    // Borrow checker demo (ERROR if uncommented)
    // let r1 = &s;
    // let r2 = &mut s; // ❌ cannot borrow `s` as mutable because it is also borrowed as immutable
    // println!("{r1}");         // r1 is used here, so its lifetime spans over r2
    // r2.push('!');             // also uses the mutable borrow

    // Scope drop demo
    {
        let r1 = &s;
        println!("Scoped borrow: {}", r1);
    } // r1 dropped here

    let r2 = &mut s;
    r2.push_str("!");
    println!("After scoped borrow: {}", s);
}

// Read-only: &str is sufficient when not mutating
fn calculate_length(s: &str) -> usize {
    s.len()
}

fn change(s: &mut String) {
    s.push_str("!");
}

🛠️ Hands-on Exercises

  1. join_non_empty(parts: &[&str], sep: &str) -> String Nối các phần tử không rỗng bằng sep. Ví dụ: ["api", "v1", "", "users"]"api/v1/users".

  2. parse_kv_line(s: &str, eq: char) -> Option<(&str, &str)> Tách cặp key–value từ một dòng cấu hình. Ví dụ: "token=abc123"Some(("token", "abc123")). Trả về None nếu không hợp lệ.

  3. get_var_or(key: &str, default: &str) -> String Lấy biến môi trường với fallback. Ví dụ: nếu APP_ENV chưa set, thì get_var_or("APP_ENV", "dev")"dev".


🐞 Common Pitfalls & Debugging Tips

Common Pitfalls

  • Anti-pattern: clone bừa bãi (.clone()) để “né ownership” → gây tốn bộ nhớ.
  • Debug: Nếu gặp borrow checker error, thử tách scope bằng { … } để drop sớm borrow trước khi tạo borrow mới.

🔄 Migration Notes (Rust 2024+)

Migration Guidance

  • Rust 1.70+ đã nới lỏng rules về lifetime elision và non-lexical lifetimes (NLL), giúp code dễ viết hơn.
  • Với edition 2024 (stable mới nhất), hầu hết ví dụ ownership/borrowing không cần sửa.
  • Dùng cargo fix --edition để migrate dự án từ 2018/2021 sang 2024.
  • Nếu upgrade crate, chỉ cần cargo update. Không có breaking change liên quan đến ownership vì đó là ngôn ngữ cốt lõi.

❓ Q&A — Common Questions

Q1. Ownership trong Rust là gì và tại sao quan trọng?

  • Ownership đảm bảo mỗi giá trị có đúng một owner tại một thời điểm. Khi owner ra khỏi scope, giá trị tự động được giải phóng. Đây là nền tảng giúp Rust quản lý bộ nhớ an toàn mà không cần GC.

Q2. Khác nhau giữa &T&mut T?

  • &T: borrow bất biến, nhiều tham chiếu song song.
  • &mut T: borrow có thể thay đổi, duy nhất một tại một thời điểm.

Q3. Khi nào xảy ra lỗi cannot borrow … as mutable more than once?

  • Khi bạn giữ đồng thời một mutable borrowít nhất một immutable borrow trong cùng scope. Compiler báo lỗi để ngăn data race.

📚 References


🌿 Wisdom Note

Đạo Đức Kinh — Chương 8

Thượng thiện nhược thủy. (The highest goodness is like water — it nourishes all things and does not contend.)

Hãy để code Rust của bạn như nước: mềm mại, rõ ràng, không tranh chấp với compiler. Khi thuận theo quy tắc ownership, bạn sẽ đạt được sự an toàn và bền vững tự nhiên.