Skip to content

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ệmCú phápÝ nghĩa
Genericfn foo<T>(arg: T)Hàm foo nhận mọi kiểu T.
Traittrait Bar { ... }Định nghĩa hành vi chung Bar.
BoundT: BarT bắt buộc phải implement Bar.
Impl Trait-> impl BarTrả về một type ẩn danh implement Bar.
Wherewhere T: BarCú pháp rõ ràng hơn cho bounds phức tạp.