1. Ownership Rules
fn main() {
// Rule 1: Mỗi value có đúng 1 owner
// Rule 2: Chỉ có 1 owner tại mọi thời điểm
// Rule 3: Khi owner ra khỏi scope, value bị drop
let s1 = String::from("hello");
let s2 = s1; // s1 bị MOVE vào s2
// println!("{}", s1); // ❌ Error: value borrowed after move
// Clone — deep copy
let s3 = s2.clone();
println!("{} {}", s2, s3); // ✅ OK
// Copy trait — stack-only data (integers, bool, char, tuples of Copy types)
let x = 5;
let y = x; // Copy, không phải move
println!("{} {}", x, y); // ✅ OK
}
// Ownership transfer qua function
fn takes_ownership(s: String) {
println!("{}", s);
} // s bị drop ở đây
fn gives_ownership() -> String {
String::from("hello")
}
2. Borrowing & References
fn main() {
let s = String::from("hello");
// Immutable reference (&T) — nhiều cùng lúc OK
let len = calculate_length(&s);
println!("{} has length {}", s, len); // s vẫn valid
// Mutable reference (&mut T) — chỉ 1 tại mỗi thời điểm
let mut s = String::from("hello");
change(&mut s);
println!("{}", s); // "hello, world"
// ❌ Không thể có &mut và & cùng lúc
// let r1 = &s;
// let r2 = &mut s; // Error: cannot borrow as mutable
}
fn calculate_length(s: &String) -> usize {
s.len()
} // s là reference nên không drop value
fn change(s: &mut String) {
s.push_str(", world");
}
3. Lifetimes
// Lifetime annotation — chỉ ra reference sống bao lâu
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
if x.len() > y.len() { x } else { y }
}
// Lifetime trong struct — struct không thể sống lâu hơn reference bên trong
struct Config<'a> {
name: &'a str,
value: &'a str,
}
impl<'a> Config<'a> {
fn display(&self) -> String {
format!("{}={}", self.name, self.value)
}
}
// 'static lifetime — sống suốt chương trình
let s: &'static str = "I live forever";
// Lifetime elision rules (compiler tự suy):
// 1. Mỗi reference parameter có lifetime riêng
// 2. Nếu chỉ 1 input lifetime → gán cho tất cả output
// 3. Nếu có &self → lifetime của self gán cho output
fn first_word(s: &str) -> &str {
// Compiler tự thêm: fn first_word<'a>(s: &'a str) -> &'a str
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[..i];
}
}
s
}
4. Borrow Checker Patterns
// Non-Lexical Lifetimes (NLL) — Rust 2021+
fn main() {
let mut data = vec![1, 2, 3];
let first = &data[0]; // immutable borrow
println!("{}", first); // last use of `first`
data.push(4); // ✅ OK — NLL biết `first` không còn dùng
}
// Splitting borrows — borrow different fields
struct Point {
x: f64,
y: f64,
}
fn update(point: &mut Point) {
let x = &mut point.x;
let y = &mut point.y;
*x += 1.0;
*y += 1.0;
}
Next article: Structures, Enums & Pattern Matching.