Giao diện
Generics & Traits Abstraction
Generics giảm trùng lặp code. Traits định nghĩa hành vi chung. Cặp đôi quyền lực của Rust.
1. Generics (Kiểu Tổng quát)
Generics cho phép viết code hoạt động với nhiều kiểu dữ liệu khác nhau mà không tốn chi phí runtime (Zero-cost abstractions nhờ Monomorphization).
Trong Function
rust
// Hàm tìm số lớn nhất hoạt động với mọi kiểu T có thể so sánh (PartialOrd) và copy được
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
println!("Largest number: {}", largest(&number_list));
let char_list = vec!['y', 'm', 'a', 'q'];
println!("Largest char: {}", largest(&char_list));
}Trong Struct & Enum
rust
struct Point<T> {
x: T,
y: T,
}
struct MixedPoint<T, U> {
x: T,
y: U,
}
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}Monomorphization
Tại compile-time, Rust "copy-paste" code generic thành các phiên bản cụ thể cho từng type bạn dùng.
rust
// Bạn viết:
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
// Compiler generate (ẩn):
struct Point_i32 { x: i32, y: i32 }
struct Point_f64 { x: f64, y: f64 }→ Không có performance penalty!
2. Traits (Đặc điểm/Hành vi)
Trait gần giống Interface trong các ngôn ngữ khác: định nghĩa functionality mà một type phải có.
Định nghĩa Trait
rust
pub trait Summary {
fn summarize(&self) -> String; // Chỉ chữ ký, không implementation
// Default implementation
fn summarize_author(&self) -> String {
format!("(Read more from {}...)", self.summarize())
}
}Implement Trait cho Type
rust
pub struct NewsArticle {
pub headline: String,
pub location: String,
pub author: String,
pub content: String,
}
impl Summary for NewsArticle {
fn summarize(&self) -> String {
format!("{}, by {} ({})", self.headline, self.author, self.location)
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}3. Trait Bounds (Ràng buộc Type)
Dùng Generics nhưng chỉ chấp nhận các type có Trait nhất định.
Cú pháp cơ bản
rust
// item phải implement Summary
pub fn notify<T: Summary>(item: &T) {
println!("Breaking news! {}", item.summarize());
}+ Syntax (Nhiều Traits)
rust
// T phải implement CẢ Summary VÀ Display
pub fn notify<T: Summary + Display>(item: &T) { ... }where Clauses (Cho dễ đọc)
Khi function signature quá dài:
rust
// Khó đọc
fn some_function<T: Display + Clone, U: Clone + Debug>(t: &T, u: &U) -> i32 { ... }
// Dễ đọc hơn
fn some_function<T, U>(t: &T, u: &U) -> i32
where
T: Display + Clone,
U: Clone + Debug,
{
// ...
}4. impl Trait Syntax
Return Type
Hữu ích khi trả về Iterator hoặc Closure (những type có tên rất phức tạp hoặc không có tên).
rust
// Trả về "thứ gì đó implement Summary"
fn returns_summarizable() -> impl Summary {
Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
}
}⚠️ LƯU Ý
impl Trait return type chỉ hoạt động nếu function trả về một type duy nhất. Nếu bạn trả về NewsArticle HOẶC Tweet tùy điều kiện → Phải dùng Trait Object Box<dyn Summary>.
5. Blanket Implementations
Implement trait cho mọi type thỏa mãn điều kiện nào đó. Ví dụ: ToString trait được implement tự động cho mọi type implement Display.
rust
impl<T: Display> ToString for T {
// ...
}Nhờ đó, bạn có thể gọi .to_string() trên bất kỳ type nào implement Display.
Bảng Tóm tắt
| Khái niệm | Cú pháp | Ý nghĩa |
|---|---|---|
| Generic | fn foo<T>(arg: T) | Hàm foo nhận mọi kiểu T. |
| Trait | trait Bar { ... } | Định nghĩa hành vi chung Bar. |
| Bound | T: Bar | T bắt buộc phải implement Bar. |
| Impl Trait | -> impl Bar | Trả về một type ẩn danh implement Bar. |
| Where | where T: Bar | Cú pháp rõ ràng hơn cho bounds phức tạp. |