Giao diện
Functional Features in Rust Idiomatic
Rust chịu ảnh hưởng mạnh từ Functional Programming (Haskell, OCaml)
Hai tính năng chính của FP trong Rust là:
- Closures: Anonymous functions (hàm ẩn danh) có thể lưu vào biến.
- Iterators: Xử lý chuỗi items, lazy evaluation và nhanh ngang code thủ công.
1. Closures: Environment Capture
Closure giống function nhưng có thể capture (nắm bắt/nhìn thấy) các biến trong scope nơi nó được định nghĩa.
Cú pháp
Định nghĩa bằng |args| body.
rust
fn main() {
let x = 4;
// Closure capture 'x' từ môi trường
let equal_to_x = |z| z == x;
let y = 4;
assert!(equal_to_x(y));
}Type Inference
Khác với fn, closure không bắt buộc khai báo type đầu vào/ra (compiler tự đoán).
rust
let example_closure = |x| x;
let n = example_closure(5);
// let s = example_closure(String::from("hello"));
// ❌ ERROR: Compiler đã lock type là integer ở lần gọi đầu tiênCapture Modes: Fn, FnMut, FnOnce
Closure capture biến theo 3 traits (tương ứng với Ownership rules):
FnOnce: Takes ownership (Move). Chỉ gọi được 1 lần.FnMut: Borrows mutably. Có thể sửa đổi captured values.Fn: Borrows immutably. Chỉ đọc.
rust
// FnMut Example
let mut list = vec![1, 2, 3];
let mut borrows_mutably = || list.push(7);
borrows_mutably();
println!("{:?}", list);move keyword: Bắt buộc closure lấy ownership (hữu ích khi dùng thread).
rust
let list = vec![1, 2, 3];
let owns_list = move || println!("{:?}", list);
// list đã bị move vào closure, không dùng được ở ngoài nữa2. Iterators: Processing Series of Items
Iterator pattern cho phép thực hiện task trên chuỗi items lần lượt.
Lazy Evaluation
Iterator trong Rust là Lazy. Nó không làm gì cho đến khi bạn gọi method "consume" nó.
rust
let v1 = vec![1, 2, 3];
// Chưa làm gì cả, chỉ tạo iterator object
let v1_iter = v1.iter();
// Giờ mới chạy
for val in v1_iter {
println!("Got: {}", val);
}Iterator Adaptors (map, filter)
Các hàm biến đổi iterator thành iterator khác. Vẫn là Lazy.
rust
let v1: Vec<i32> = vec![1, 2, 3];
// Map + 1
// collect() là hàm "consume", kích hoạt chain chạy và gom kết quả về Vec
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
assert_eq!(v2, vec![2, 3, 4]);rust
// Filter lấy số lẻ
let v3: Vec<_> = v1.into_iter().filter(|x| x % 2 != 0).collect();Iterator Consumers (sum, fold)
Các hàm "ăn" iterator và trả về giá trị cuối cùng.
rust
let v1 = vec![1, 2, 3];
let total: i32 = v1.iter().sum(); // 63. Performance: Loop vs Iterator
Bạn có thể lo lắng Iterator chậm hơn Loop for thủ công?
SỰ THẬT: Iterator trong Rust thường NHANH HƠN hoặc BẰNG Loop.
Đây là Zero-cost Abstraction. Compiler (LLVM) optimize iterators rất tốt (unrolling, vectorization).
💡 BENCHMARK NOTE
Đừng ngại dùng Iterator. Nó ngắn gọn, an toàn (không bounds check lỗi) và cực nhanh. Cha đẻ C++ (Bjarne Stroustrup) cũng ước C++ ranges được như này.
4. Ví dụ thực tế: Cải tiến code với FP
Code ban đầu (Imperative)
rust
fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut results = Vec::new(); // Mutable state
for line in contents.lines() {
if line.contains(query) {
results.push(line);
}
}
results
}Code cải tiến (Idiomatic FP)
rust
fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
contents
.lines()
.filter(|line| line.contains(query))
.collect()
}Ngắn hơn, rõ ý hơn, không cần mut, và performance tương đương.
Bảng Tóm tắt Iterators
| Method | Loại | Mô tả |
|---|---|---|
iter() | Constructor | Tạo iterator các references &T. |
into_iter() | Constructor | Tạo iterator các owned values T (consume collection). |
iter_mut() | Constructor | Tạo iterator các mutable references &mut T. |
map(f) | Adaptor | Biến đổi từng phần tử. |
filter(f) | Adaptor | Giữ lại phần tử thỏa điều kiện. |
collect() | Consumer | Biến iterator thành collection (Vec, String...). |