
Rust nổi tiếng với mô hình ownership (sở hữu) và lifetime (vòng đời) độc đáo — hai cơ chế cốt lõi giúp ngôn ngữ này đảm bảo an toàn bộ nhớ mà không cần garbage collector. Hiểu sâu hai khái niệm này là chìa khóa để viết code Rust hiệu quả, tránh borrow checker error và tận dụng tối đa hiệu năng zero-cost abstraction.

Ownership trong Rust là gì?
Ownership là hệ thống quy tắc quản lý bộ nhớ tại compile-time. Mỗi giá trị trong Rust có chính xác một owner (chủ sở hữu) — biến giữ giá trị đó. Khi owner ra khỏi scope, giá trị tự động bị drop (giải phóng bộ nhớ). Ba quy tắc cơ bản:
- Mỗi giá trị có một owner duy nhất
- Chỉ có một owner tại một thời điểm
- Khi owner hết scope, giá trị bị drop
Ví dụ cơ bản về move semantics:
fn main() {
let s1 = String::from("hello");
let s2 = s1; // ownership chuyển từ s1 sang s2 (move)
// println!("{}", s1); // Lỗi: s1 không còn hợp lệ
println!("{}", s2); // OK: s2 là owner mới
}

Borrowing: mượn thay vì chuyển quyền
Để tránh move không cần thiết, Rust cho phép borrowing (vay mượn) thông qua reference (&T). Có hai loại reference:
- Immutable reference (&T): có thể tạo nhiều cùng lúc, không cho sửa đổi
- Mutable reference (&mut T): chỉ cho phép một tại một thời điểm, cho phép sửa đổi
Quy tắc borrowing (borrow checker enforce tại compile-time):
- Bao nhiêu immutable reference cũng được, MIỄN không có mutable reference nào đang tồn tại
- Chỉ được MỘT mutable reference, và KHÔNG được immutable reference nào cùng lúc
- Reference không được sống lâu hơn dữ liệu nó tham chiếu (dangling reference)
Ví dụ borrowing an toàn:
fn tinh_do_dai(s: &String) -> usize {
s.len()
} // s ra khỏi scope nhưng KHÔNG drop String gốc
fn main() {
let s = String::from("rust");
let len = tinh_do_dai(&s); // borrow immutable
println!("Độ dài: {}", len); // s vẫn dùng được
}
Lifetime: đảm bảo reference hợp lệ
Lifetime (thường ký hiệu 'a, 'b…) là metadata tại compile-time chỉ ra reference sống bao lâu. Mọi reference trong Rust đều có lifetime — compiler tự suy diễn (elision) trong nhiều trường hợp đơn giản, nhưng code phức tạp cần annotation tường minh.
Ví dụ function cần lifetime annotation:
// Không annotation: compiler không biết trả về reference của x hay y
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
Quy tắc lifetime elision (Rust 2018+):
- Mỗi parameter là reference có lifetime riêng
- Nếu chỉ có một input lifetime → gán cho tất cả output lifetime
- Nếu có
&selfhoặc&mut self→ gán lifetime của self cho output
Lifetime trong struct và impl
Khi struct chứa reference, phải khai báo lifetime:
struct Excerpt<'a> {
part: &'a str,
}
impl<'a> Excerpt<'a> {
fn level(&self) -> i32 { 3 }
fn announce_and_return_part(&self, announcement: &str) -> &str {
println!("Thông báo: {}", announcement);
self.part
}
}
Static lifetime (‘static): reference sống suốt chương trình (string literal, global data). Dùng khi cần data không bao giờ drop.
Advanced: Higher-Ranked Trait Bounds (HRTB)
HRTB cho phép function generic over lifetime — dùng khi closure/function parameter cần hoạt động với bất kỳ lifetime nào:
fn call_with_str<F>(f: F)
where
F: for<'a> Fn(&'a str),
{
let s = String::from("hello");
f(&s);
}
Non-Lexical Lifetimes (NLL)
Rust 2018 giới thiệu NLL — borrow checker thông minh hơn, hiểu scope dựa trên usage thực tế thay vì lexical block. Code cũ bị reject giờ có thể compile:
fn main() {
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} {}", r1, r2); // r1, r2 dùng xong ở đây
let r3 = &mut s; // OK với NLL: r1, r2 không còn "sống"
println!("{}", r3);
}
Bảng so sánh: Ownership vs Borrowing vs Lifetime
| Khái niệm | Mục đích | Syntax | Khi nào dùng |
|---|---|---|---|
| Ownership | Quyền kiểm soát bộ nhớ | let x = T |
Mặc định cho mọi biến |
| Immutable borrow | Đọc data không lấy ownership | &T |
Function chỉ đọc, nhiều caller cùng lúc |
| Mutable borrow | Sửa data không lấy ownership | &mut T |
Function cần sửa, độc quyền truy cập |
| Lifetime annotation | Ràng buộc scope reference | 'a |
Struct chứa ref, function trả ref từ input |
Best practices thực chiến
- Ưu tiên borrowing thay vì clone:
&Tzero-cost,.clone()tốn heap allocation - Dùng lifetime elision khi có thể: ít annotation hơn = code dễ đọc hơn
- Tránh &’static trừ khi cần thiết: gắn cứng lifetime làm code cứng nhắc
- Hiểu drop order: fields drop theo thứ tự khai báo, struct drop sau fields
- Dùng
std::mem::dropthủ công khi cần drop sớm trước khi ra scope

Nắm vững ownership, borrowing và lifetime biến Rust từ “ngôn ngữ khó học” thành công cụ mạnh mẽ xây dựng hệ thống an toàn, nhanh, không race condition. Hãy bắt đầu với các ví dụ nhỏ, để borrow checker dẫn dắt — nó là người bạn đồng hành tin cậy nhất trong hành trình Rust.
Nguồn tham khảo: The Rust Programming Language – Ownership, The Rustonomicon – Lifetimes
