30 Ngày học Rust - Day 4: Ownership - Khái niệm định hình cỗ thần khí Rust
Day 4: Bí mật lớn nhất khiến Rust trở thành ngôn ngữ bất bại: Quy tắc Ownership. Tại sao Rust không cần Máy dọn rác (Garbage Collector) nhưng vẫn an toàn bộ nhớ tĩnh tuyệt đối?

Garbage Collector? Không, chúng tôi dùng Ownership!
Trong suốt lịch sử máy tính, con người chống lại “Lỗi quản lý bộ nhớ” (Memory Leak, Segfault) bằng 2 con đường:
- Lối đi của C/C++: Lập trình viên phải TỰ cấp phát và TỰ đóng RAM bằng tay (malloc và free). Hậu quả? Quên đóng thì RAM tràn, đóng nhầm 2 lần thì app Crash. 70% số lượng lỗ hổng bảo mật của Microsoft đều đến từ nhóm lỗi C này.
- Lối đi của Java / JS / Go: Nhúng một ông Bảo vệ hút rác chạy ngầm tên là Garbage Collector (GC). Lập trình viên cứ vứt rác, có ông thu dọn. Đổi lại, app thỉnh thoảng sẽ “giật lag” lúc máy dọn rác chạy, gây nghẽn tốc độ.
Rust chọn con đường số 3: Đoạn tuyệt hoàn toàn với GC, cũng cấm luôn DEV nhặt rác thủ công. Rust thay thế tất cả bằng bùa phép: Tư duy Ownership (Quyền Sở Hữu). Bộ luật này không chạy trên thực địa, nó chạy ngay lúc bạn Compile (Biên dịch).
1. Ba điều luật vàng của Ownership
Trình biên dịch Rust (Rustc) có tên sát thủ The Borrow Checker kiểm tra gắt gao đoạn code của bạn. Nếu vi phạm 3 luật sau, Compile rớt.
- Luật 1: Từng giá trị trong Rust chỉ có duy nhất MỘT biến gọi là
Owner(Chủ sở hữu). - Luật 2: Tại một thời điểm, chỉ có DUY NHẤT 1
Ownerđược tồn tại. Không có chế độ vợ lẽ hai chồng. - Luật 3: Khi
Ownerđi chệch khỏi phạm vi sống (Scope của nó kết thúc bằng dấu đóng ngoặc}), thì cái giá trị kia LẬP TỨC LĂN RA CHẾT và RAM được tự động quét dọn.
2. Di chuyển (Move) - Khái niệm gây “Lú” nhất toàn cõi Rust
Hãy xem ví dụ với kiểu chuỗi String lừng danh:
fn main() {
let s1 = String::from("hello");
let s2 = s1; // Tôi gán s2 bằng s1
println!("In s1 nào: {}", s1);
}Kết quả nếu chạy: TRÌNH BIÊN DỊCH BÁO LỖI (MÀU ĐỎ).
Tại sao? Bên giới Java hay Python, dòng số 3 chỉ tạo thêm 1 con chó nhưng có 2 cái dây xích (s1 và s2 cùng trỏ vào 1 con chó hello ở Heap RAM). Nhưng nếu để Rust làm vậy thì vi phạm Luật 2: “Có 2 Owner”. Lỡ Scope chạy xong, cả s1 và s2 cùng hô lệnh “Hãy giải phóng RAM”, dẫn đến thảm họa Double Free!
Vì vậy, Rust chọn giải pháp cực đoan nhưng hoàn hảo: Ngay dòng lệnh let s2 = s1, Rust “hủy giầy khai sinh” cùa s1 ngay lập tức. Chuỗi “hello” chính thức chuyển giao Chủ sở hữu sang s2. Hành động này gọi là Move. s1 bây giờ là một âm hồn vô dụng, gọi tên nó ra để println! sẽ dẫn đến tử hình.
3. Nhân bản bộ nhớ bằng clone
Thế nếu tôi cứng đầu muốn s1 và s2 độc lập, đều in ra được thì sao? Hãy xé mảng bộ nhớ làm 2 mảnh giống hệt nhau bằng phương thức clone:
let s1 = String::from("hello");
let s2 = s1.clone();
// Việc này cực kỳ tốn RAM (Deep copy), nhưng an toàn tuyệt đối.Câu hỏi thường gặp (FAQ)
Vậy sao các số nguyên cơ bản (let x = 5; let y = x;) không bị lỗi giống chuỗi String?
Vì x = 5 là một giá trị kích thước tĩnh, đã biết trước. Trình biên dịch ném nó hẳn vào bộ nhớ siêu tốc (The Stack RAM). Stack thao tác rất nhanh. Hành động copy đè số 5 sang y tốn đúng 1 tích tắc. Do rẻ mạt nên kiểu dữ liệu này được gán mác Copy trait. Hàm Move quyền sở hữu chỉ xảy ra trên các kiểu dữ liệu mọc ở the Heap (kích thước lớn, biến thiên như Chuỗi String, Mảng Vector).
Việc kiểm soát Ownership có làm mất tốc độ trong lúc chạy (Runtime) không?
Tuyệt đối KHÔNG. Đó là ma thuật của Rust (Zero-cost Abstraction). Việc vứt bắt Owner này hoàn toàn là quá trình kiểm tra não trên tờ giấy của gã Compiler (Lúc bạn gõ gõ code IDE). Đến khi sinh mã máy .exe cuối cùng, code của bạn đã chứng minh sự trong sạch. Nó sải cánh thẳng tiến trên vi xử lý mà không cần đẻ thêm bất cứ tiến trình ngầm nào bảo kê. Nhanh bạo lực như C++.
Sẵn sàng cho Ngày 5? Ownership chặt chẽ tới mức thật ức chế nếu chúng ta muốn truyền biến vào một cái Hàm (Truyền vào là truyền quyền đi luôn). Nếu chỉ muốn dùng chung món đồ mà không làm đổi Giấy tờ nhà thì sao? Cùng hít thở với [Day 5: References & Borrowing - Kẻ Vay Mượn Thông Thái].
Chuỗi bài viết
30 Ngày Trở Thành Rustacean Tinh Hoa
Phần 4 / 30
- Phần 1 30 Ngày học Rust - Day 1: Lời chào thế giới và Vũ khí Cargo
- Phần 2 30 Ngày học Rust - Day 2: Biến, Bất biến (Mutability) và Shadowing
- Phần 3 30 Ngày học Rust - Day 3: Luồng điều khiển (Control Flow) và sức mạnh của Match
- Phần 4 30 Ngày học Rust - Day 4: Ownership - Khái niệm định hình cỗ thần khí Rust
- Phần 5 30 Ngày học Rust - Day 5: Khóa học nhặt đồ chung với References & Borrowing
- Phần 6 30 Ngày học Rust - Day 6: Đắp nặn dự án với Structs và Methods
- Phần 7 30 Ngày học Rust - Day 7: Quyền năng vô song của Enums và Pattern Matching
- Phần 8 30 Ngày học Rust - Day 8: Quản lý dự án với Packages, Crates và Modules
- Phần 9 30 Ngày học Rust - Day 9: Các bộ sưu tập chung (Vectors, Strings, Hash Maps)
- Phần 10 30 Ngày học Rust - Day 10: Trị dứt điểm Ác mộng Lỗi (Error Handling)
- Phần 11 30 Ngày học Rust - Day 11: Generics - Ma thuật Đa hình kiểu dữ liệu
- Phần 12 30 Ngày học Rust - Day 12: Traits - Kẻ ban phát quyền năng và Lập pháp Hành vi
- Phần 13 30 Ngày học Rust - Day 13: Vượt qua Boss cuối 'Lifetimes' - Sinh Mệnh Biến
- Phần 14 30 Ngày học Rust - Day 14: Tận diệt Bug từ trứng nước bằng Automated Tests
- Phần 15 30 Ngày học Rust - Day 15: Thực chiến Build Command Line App (CLI) đầu đời
- Phần 16 30 Ngày học Rust - Day 16: Functional Magic chốn trần gian (Closures & Iterators)
- Phần 17 30 Ngày học Rust - Day 17: Quyền năng của Smart Pointers
- Phần 18 30 Ngày học Rust - Day 18: Chinh phục Da luồng (Concurrency) - Cú đâm quyết định của Rust
- Phần 19 30 Ngày học Rust - Day 19: Tranh cãi Lập trình hướng đối tượng (OOP) trong Rust
- Phần 20 30 Ngày học Rust - Day 20: Mổ xẻ nghệ thuật Advanced Pattern Matching
- Phần 21 30 Ngày học Rust - Day 21: Sức mạnh tối thượng của Advanced Traits
- Phần 22 30 Ngày học Rust - Day 22: Về Phe Bóng Tối với Unsafe Rust
- Phần 23 30 Ngày học Rust - Day 23: Quyền năng của Đấng Tạo Hóa (Declarative Macros)
- Phần 24 30 Ngày học Rust - Day 24: Siêu Năng Lực Procedural Macros (Macro Thủ Tục)
- Phần 25 30 Ngày học Rust - Day 25: Xây dựng TCP Web Server Đa Luồng (Phần 1: Lõi Socket)
- Phần 26 30 Ngày học Rust - Day 26: Xây dựng TCP Web Server Đa Luồng (Phần 2: Bắn trả File HTML)
- Phần 27 30 Ngày học Rust - Day 27: Xây dựng TCP Web Server Đa Luồng (Phần 3: The Thread Pool)
- Phần 28 30 Ngày học Rust - Day 28: Xây dựng TCP Web Server Đa Luồng (Phần 4: Graceful Shutdown)
- Phần 29 30 Ngày học Rust - Day 29: Lên đỉnh Web Server Thực Chiến với Axum và Tokio
- Phần 30 30 Ngày học Rust - Day 30: Vượt Vọng Vàng - Đúc Kết Hành Trình Rustacean Tinh Hoa