Lesson 6 — Traits, Generics, and Abstractions
🎯 Learning Objectives
- Hiểu traits là gì và cách định nghĩa hành vi chung cho nhiều kiểu.
- Biết cách dùng generics để viết hàm và struct tổng quát, tránh lặp code.
- Thực hành xây dựng abstractions để code dễ mở rộng và tái sử dụng.
✅ Explanation & Key Concepts
Trait = tập hợp method signatures (và có thể default impl). Kiểu nào implement trait thì có thể dùng trait đó.
💻 Example Implementation
Cargo.toml
[package]
name = "lesson06_traits_generics"
version = "0.1.0"
edition = "2024"
src/main.rs
// Define a trait trait Summarize { fn summary(&self) -> String; } // Implement for a struct struct Article { title: String, author: String, } impl Summarize for Article { fn summary(&self) -> String { format!("{} by {}", self.title, self.author) } } // Generic function with trait bound fn notify<T: Summarize>(item: &T) { println!("Notification: {}", item.summary()); } fn main() { let art = Article { title: "Async in Rust".to_string(), author: "dp".to_string(), }; notify(&art); }
🛠️ Hands-on Exercises
- Basic: Tạo trait
Printablevới hàmprint(&self); implement choStringvài32. - Intermediate: Viết hàm generic
max<T: Ord>(list: &[T]) -> Option<&T>để tìm phần tử lớn nhất. - Challenge: Định nghĩa trait
Storage<K,V>với methodset/get; implement choHashMap<K,V>.
🐞 Common Pitfalls & Debugging Tips
- Quên thêm trait bound (
T: Trait) khi dùng method từ trait. - Nhầm lẫn giữa
impl Traitvà generic<T: Trait>. - Trait object (
Box<dyn Trait>) không giống generics: dùng khi cần dynamic dispatch.
❓ Q&A — Common Questions
Q1. Trait vs Interface (ở ngôn ngữ khác)?
- Giống nhau ở việc định nghĩa hành vi. Khác ở chỗ trait có default implementation, có thể compose nhiều trait cho cùng một kiểu, và trait bounds mạnh mẽ trong generic functions/structs.
Q2. Khi nào dùng Generics vs Macro vs Trait Object?
- Generics → monomorphization, an toàn & nhanh, compile-time polymorphism.
- Macro → sinh code (syntax-level), không phải abstraction runtime.
- Trait object (
dyn Trait) → khi cần chọn hành vi lúc runtime (dynamic dispatch) hoặc cần tính đồng nhất kiểu động trong containers.
Q3. Kết hợp Traits + Generics để tạo API gọn & mạnh?
- Dùng trait bounds:
fn f<T: TraitA + TraitB>(x: T). Tách behavior thành traits nhỏ, cung cấp default impl, và dùngimpl Traittrong chữ ký hàm để đơn giản hóa API bên ngoài.
🔄 Migration Notes (Rust 2024+)
impl Traitngày càng được ưu tiên vì code gọn.- Rust 2024 cải thiện inference trait bound trong một số ngữ cảnh.
async fntrong trait đang dần được stable (hiện cầnasync-traitcrate nếu dùng rộng).
📚 References
📖 Glossary of Terms
- Trait: tập hợp method signatures để chia sẻ hành vi.
- Generic: tham số hóa kiểu, giúp code tổng quát.
- Trait bound: ràng buộc yêu cầu một kiểu phải implement trait.
- Trait object: giá trị động (
dyn Trait), hỗ trợ dynamic dispatch.
🌿 Wisdom Note
Tam thập phúc, cộng nhất hồ.
Thirty spokes share the wheel’s hub; it is the center hole that makes it useful.
Traits và generics cũng vậy: chính khoảng trống (abstraction) làm cho code có sức mạnh mở rộng.