· Phạm Thành Nam · Ngôn ngữ Rust · 4 phút đọc

30 Ngày học Rust - Day 11: Generics - Ma thuật Đa hình kiểu dữ liệu

Day 11: Code ít lại, tái sử dụng nhiều hơn. Khám phá cách Generics giúp tạo ra các hàm và cấu trúc dữ liệu không phụ thuộc vào một kiểu cố định.

Day 11: Code ít lại, tái sử dụng nhiều hơn. Khám phá cách Generics giúp tạo ra các hàm và cấu trúc dữ liệu không phụ thuộc vào một kiểu cố định.

Generics: Thoát khỏi sự kìm kẹp của Type cứng

Trong các ngôn ngữ định kiểu tĩnh (Statically Typed) như Java, C++ hay Rust, khi bạn viết một hàm tìm giá trị lớn nhất của 2 số nguyên, bạn phải gõ:

fn so_lon_nhat(a: i32, b: i32) -> i32 { ... }

Nếu ngày mai dự án cần tìm số lớn nhất của hai số thực (f64), hoặc hai ký tự (char), bạn lại phải hùng hục copy dán code ra thêm 2 hàm mới tinh mang tên so_thuc_lon_nhat, ki_tu_lon_nhat. Quá tồi tệ trong việc nguyên lý lập trình DRY (Don’t Repeat Yourself).

Giải pháp cho vấn đề này là Generics — thay vì ép cứng nó là i32 hay f64, ta truyền vào một CÁI TÊN THAY THẾ (Thường viết tắt là T - Type).

Sơ đồ nguyên lý hoạt động của Generics

1. Viết Generics trong Hàm (Function)

Hãy xem cách chúng ta bẻ gãy mọi khuôn mẫu:

// Khai báo <T> cho Rust biết: "T là một kiểu bất kỳ do khách hàng quyết định"
// Yêu cầu `PartialOrd` là bắt buộc để Rust biết T có thể so sánh lớn/nhỏ
fn so_lon_nhat<T: std::cmp::PartialOrd>(a: T, b: T) -> T {
    if a > b {
        a
    } else {
        b
    }
}

fn main() {
    println!("Lớn nhất: {}", so_lon_nhat(50, 20));       // T tự động thế thành i32
    println!("Lớn nhất: {}", so_lon_nhat(50.5, 90.1));   // T tự động thế thành f64
    println!("Lớn nhất: {}", so_lon_nhat('a', 'z'));     // T thế thành char
}

Bây giờ hàm so_lon_nhat có thể nuốt mọi kiều dữ liệu tồn tại trên địa cầu, miễn là loại đó thỏa mãn điều kiện CÓ THỂ SO SÁNH (PartialOrd).

2. Viết Generics trong Cấu trúc Dữ liệu (Struct & Enum)

Ở những bài trước, bạn đã vô tình dùng Generics cực kì nhuần nhuyễn mà không hề hay biết!

Vec<T> là một Struct Generics. Vector Mảng này được thiết kế trống rỗng về kiểu. Khi bạn chạy Vec::<i32>::new(), bạn đang bơm xi lăng i32 vào thế chỗ chữ T. Hai vị cứu tinh của Rust là OptionResult cũng vậy:

enum Option<T> {
    Some(T),
    None,
}

enum Result<T, E> { // E đại diện cho Kiểu của Lỗi (Error)
    Ok(T),
    Err(E),
}

Khởi tạo Trục tọa độ 2D đa hình:

struct ToaDo<T, U> {
    x: T,
    y: U,
}

// X có thể là i32, Y có thể là số thực f64!
let diem = ToaDo { x: 5, y: 10.5 };

Câu hỏi thường gặp (FAQ)

Việc dùng Generics có làm chậm ứng dụng khi chạy như ở Java / C# không?

Một tính năng GÂY THƯƠNG NHỚ của Rust là Monomorphization (Đơn hình hóa). Lúc bạn gõ code T, nó đa hình. Nhưng đến lúc bạn Compile (Biên dịch) bằng Cargo, gã Compiler tự động chui vào code của bạn, quét xem bạn đã lấy hàm đó gán mấy kiều thực tế. Nếu nó thấy bạn gọi với i32f64, Cỗ máy Compilation âm thầm Dịch và COPY RA 2 HÀM con nhộng riêng biệt ứng với đúng kiểu i32f64 đưa xuống vi xử lý CPU. Kết quả: Tốc độ chạy lúc Runtime (Lúc khách hàng xài app) là NHANH BẠO LỰC CỰC ĐẠI, tốc độ vút ngang bằng việc bạn gõ code tường minh thủ công. Điểm trừ duy nhất là dạn phình to file .exe lúc build (Compile time dài hơn một tẹo).


Sẵn sàng cho Ngày 12? Việc khống chế chữ T không được biến thành Array mảng nếu mình mang đem Hàm Phép Cộng là do chức năng của một Kẻ canh gác tên là Trait. Ngày mai chúng ta sẽ đào sâu khái niệm Mỏ Vàng này tại: [Day 12: Traits - Lập pháp Hành vi].

Chuỗi bài viết

30 Ngày Trở Thành Rustacean Tinh Hoa

Phần 11 / 30

30 bài viết
  1. Phần 1 30 Ngày học Rust - Day 1: Lời chào thế giới và Vũ khí Cargo
  2. Phần 2 30 Ngày học Rust - Day 2: Biến, Bất biến (Mutability) và Shadowing
  3. Phần 3 30 Ngày học Rust - Day 3: Luồng điều khiển (Control Flow) và sức mạnh của Match
  4. Phần 4 30 Ngày học Rust - Day 4: Ownership - Khái niệm định hình cỗ thần khí Rust
  5. Phần 5 30 Ngày học Rust - Day 5: Khóa học nhặt đồ chung với References & Borrowing
  6. Phần 6 30 Ngày học Rust - Day 6: Đắp nặn dự án với Structs và Methods
  7. Phần 7 30 Ngày học Rust - Day 7: Quyền năng vô song của Enums và Pattern Matching
  8. Phần 8 30 Ngày học Rust - Day 8: Quản lý dự án với Packages, Crates và Modules
  9. Phần 9 30 Ngày học Rust - Day 9: Các bộ sưu tập chung (Vectors, Strings, Hash Maps)
  10. Phần 10 30 Ngày học Rust - Day 10: Trị dứt điểm Ác mộng Lỗi (Error Handling)
  11. Phần 11 30 Ngày học Rust - Day 11: Generics - Ma thuật Đa hình kiểu dữ liệu
  12. Phần 12 30 Ngày học Rust - Day 12: Traits - Kẻ ban phát quyền năng và Lập pháp Hành vi
  13. Phần 13 30 Ngày học Rust - Day 13: Vượt qua Boss cuối 'Lifetimes' - Sinh Mệnh Biến
  14. Phần 14 30 Ngày học Rust - Day 14: Tận diệt Bug từ trứng nước bằng Automated Tests
  15. Phần 15 30 Ngày học Rust - Day 15: Thực chiến Build Command Line App (CLI) đầu đời
  16. Phần 16 30 Ngày học Rust - Day 16: Functional Magic chốn trần gian (Closures & Iterators)
  17. Phần 17 30 Ngày học Rust - Day 17: Quyền năng của Smart Pointers
  18. Phần 18 30 Ngày học Rust - Day 18: Chinh phục Da luồng (Concurrency) - Cú đâm quyết định của Rust
  19. Phần 19 30 Ngày học Rust - Day 19: Tranh cãi Lập trình hướng đối tượng (OOP) trong Rust
  20. Phần 20 30 Ngày học Rust - Day 20: Mổ xẻ nghệ thuật Advanced Pattern Matching
  21. Phần 21 30 Ngày học Rust - Day 21: Sức mạnh tối thượng của Advanced Traits
  22. Phần 22 30 Ngày học Rust - Day 22: Về Phe Bóng Tối với Unsafe Rust
  23. Phần 23 30 Ngày học Rust - Day 23: Quyền năng của Đấng Tạo Hóa (Declarative Macros)
  24. Phần 24 30 Ngày học Rust - Day 24: Siêu Năng Lực Procedural Macros (Macro Thủ Tục)
  25. Phần 25 30 Ngày học Rust - Day 25: Xây dựng TCP Web Server Đa Luồng (Phần 1: Lõi Socket)
  26. Phần 26 30 Ngày học Rust - Day 26: Xây dựng TCP Web Server Đa Luồng (Phần 2: Bắn trả File HTML)
  27. Phần 27 30 Ngày học Rust - Day 27: Xây dựng TCP Web Server Đa Luồng (Phần 3: The Thread Pool)
  28. Phần 28 30 Ngày học Rust - Day 28: Xây dựng TCP Web Server Đa Luồng (Phần 4: Graceful Shutdown)
  29. Phần 29 30 Ngày học Rust - Day 29: Lên đỉnh Web Server Thực Chiến với Axum và Tokio
  30. Phần 30 30 Ngày học Rust - Day 30: Vượt Vọng Vàng - Đúc Kết Hành Trình Rustacean Tinh Hoa

Bình luận

Quay lại Blog

Bài viết liên quan

Xem tất cả bài viết »