30 Ngày học Rust - Day 5: Khóa học nhặt đồ chung với References & Borrowing
Day 5: Phá giải ức chế của Ownership. Cách truyền tham số cho hàm mà không bị mất quyền sơ hữu bằng cơ chế Tham Chiếu (References) và Mượn đồ (Borrowing) trong Rust an toàn.

Khi “Sở hữu” trở thành sự kiềm cặp
Ở Ngày 4, chúng ta học rằng đưa Data ra khỏi ngoặc sẽ làm thay Chủ (Move). Điều này sinh ra một bi kịch khi bạn dùng Hàm (Functions):
fn tinh_do_dai(s: String) -> usize {
s.len()
}
fn main() {
let ten = String::from("Nam");
let chieu_dai = tinh_do_dai(ten); // "ten" bị Mất Giấy Chuyển Nhượng cho hàm!
println!("Tên là {}", ten); // LỖI COMPILER! Giá trị của "ten" đã ra đi mãi mãi...
}Bạn chỉ muốn một hàm soi xét độ dài từ, nhưng hàm đó nuốt chửng luôn biến của bạn. Mọi giải pháp như việc bắt hàm đó phải return ném trả lại miếng string cũ là quá đần độn. Xin giới thiệu: Tham Chiếu và Mượn (References & Borrowing).
1. Bùa hộ mệnh: Ký tự Ampersand &
Trong thế giới thuật ngữ Rust, Reference (Tham chiều) là địa chỉ cầm tờ giấy trỏ xuống tận gốc gác dữ liệu thay vì việc cầm luôn tờ đăng ký kết hôn của dữ liệu. Biểu tượng là dấu và (&).
Hãy sửa code ở trên:
fn tinh_do_dai(s: &String) -> usize { // Khai báo: Tôi chỉ xin NGÓ (Reference)
s.len()
}
fn main() {
let ten = String::from("Nam");
let chieu_dai = tinh_do_dai(&ten); // Gửi đi cái Bóng (Reference), giữ lại cái Thân
println!("Tên là: {}, độ dài: {}", ten, chieu_dai); // Code chạy mượt mà!
}Hành động chúng ta tạo ra một tham chiếu &ten và đẩy vào hàm được gọi bằng cái tên hành động là Borrowing (Mượn đồ). Hàm tinh_do_dai mượn ô xe, đếm số ghế bên trong, xong kết thúc hàm trả lại ô xe. Nó không được phép thóa mạ bán dỡ chiếc xe đó vì nó đéo có quyền sở hữu!
2. Bạn không thể thay đổi thứ bạn vay mượn
Giống như ngoài đời, mượn củ cà rốt thì lúc trả không thể thành đĩa nộm. Tham chiếu mặc định là Bất biến.
fn thay_doi(s: &String) {
s.push_str(", chao ban"); // LỖI! Dám chỉnh sửa đồ đi mượn à?
}3. Sám hối trước Borrow Checker: Mutable References
Nếu tôi khăng khăng muốn sửa rễ gốc qua biến tham chiếu thỉ sao? Cần phải làm đúng nghi thức: Khai báo Bản tính biến đổi (Mutable) từ tận cành cho tới lá. Tức là gắn &mut.
fn main() {
let mut ten = String::from("Hello"); // Cành: Khai tử tĩnh báo
thay_doi(&mut ten); // Xin phép tham chiếu Động
println!("{}", ten);
}
fn thay_doi(s: &mut String) { // Đón nhận tham chiếu Động
s.push_str(", world");
}Bộ Nhị Cấm Cung Lỗi của Ngài Borrow Checker
Sức ảnh hưởng của đoạn code tuy hoàn mĩ nhưng hệ thống ngăn lỗi sập data của Ngài Checking cấm bạn 2 luật cốt cán:
- Bạn có thể có Nhiều tham chiếu dạng đọc
&T, cùng lúc thoải mái. - Hoặc, Bạn chỉ có DUY NHẤT 1 tham chiếu dạng viết
&mut Ttrong cùng lúc Scope đoạt được.
CẤM: Vừa có ông ngực đọc (
&T), lại vừa có ông đi sửa (&mut T) ngay cạnh nhau ở cùng giây phút. Sinh ra thảm họa thay đổi ngầm đứt mạng Database.
Câu hỏi thường gặp (FAQ)
Rút cụt lại thì Ownership và Borrowing bảo vệ ta khỏi cái gì?
Nó chặn vĩnh viễn thuật ngữ kinh dị trong thế giới Hacker siêu đẳng: Data Races (Thi chạy tranh dữ liệu). Việc quy định chỉ 1 người có giấy viết ở 1 tích tắc giúp việc gọi API song song ở 5.000 luồng đồng thời (Concurrency) đạt mốc an toàn 100%. Sẽ không có việc 2 lệnh cùng trừ thẳng $1000 vào băng ngân hàng mà ra sai phép tính.
Có hiện tượng Tham Chiếu Nguy Cấp (Dangling References) ở Rust không?
Con trỏ lủng lẳng là bug đau đớn nhất ở C (Trỏ đến Object đã bị xoá). Ở Rust, Borrow Checker dập chết bug này ngay khi bạn code nhờ vào “Lifetime”. Biến mượn đồ không thể nào bay nhảy với tuổi thọ vĩnh cửu trong khi thằng chủ đồ bị diệt. Rust sẽ mắng bạn ngay lập tức nếu bạn cố trả về &String của một biến vừa chết trong hàm.
Sẵn sàng cho Ngày 6? Xong 5 ngày đầu, bạn đã vượt qua thung lũng kinh hoàng nhất của Rust. Chúng đi bộ xuống dốc thư giãn với việc quy hoạch Đống dữ liệu bừa bãi thành khối cấu trúc trong [Day 6: Structs và Methods].
Chuỗi bài viết
30 Ngày Trở Thành Rustacean Tinh Hoa
Phần 5 / 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