30. tháng 5 2025
Trong khi đang xem một đoạn mã Rust từ VSBET thư viện phân tích văn bản trên GitHub, tôi đã gặp định nghĩa kiểu enum như sau:
#[derive(Debug)]
pub enum Line {
Comment(String),
Metadata(String, String),
Entry(DictEntry<String>), [j88 online](/blog/php-expression-and-at-symbol-is-wha/)
Empty,
Incorrect,
}
Tôi thực sự bị choáng ngợp. Tại sao mỗi mục lại có thể ghi chú kiểu dữ liệu phía sau? (Lúc này tôi vẫn chưa liên tưởng tới Option). Sáng hôm đó, trên đường đi làm, tôi lật nhanh tài liệu chính thức của Rust và đã tìm ra câu trả lời (dễ hơn rất nhiều so với việc đọc cuốn sách "The Rust Programming Language"). Ví dụ về cấu trúc lưu trữ địa chỉ IP theo cách hiểu cũ của tôi về enum sẽ được định nghĩa như sau:
enum IpAddrKind {
V4,
V6,
}
struct IpAddr {
kind: IpAddrKind,
address: String,
}
let home = IpAddr {
kind: IpAddrKind::V4,
address: String::from("127.0.0.1"),
};
let loopback = IpAddr {
kind: IpAddrKind::V6,
address: String::from("::1"),
};
Tuy nhiên, Rust cho phép đơn giản hóa định nghĩa kiểu:
enum IpAddr {
V4(String),
V6(String),
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
Trong khi các cấu trúc (structs) giúp bạn nhóm các trường và dữ liệu liên quan lại với nhau, ví dụ như một hình chữ nhật với chiều rộng và chiều cao; thì các kiểu enum cung cấp cách để nói rằng một giá trị thuộc một trong số các giá trị khả dĩ. Nhìn vào định nghĩa của enum, rõ ràng không có gì sai cả, Rust đã đưa việc sử dụng enum lên một tầm cao mới... Quay trở lại đoạn mã ban đầu, giờ nó trông dễ hiểu hơn nhiều. Thật vậy, một dòng ghi chép văn bản txt có thể là một dữ liệu, một chú thích, hoặc một thông tin khác. Cuối cùng, mỗi dòng được trừu tượng hóa thành một subtype trong enum Line.
Ngôn ngữ lập trình Rust không chứa kiểu Null. Điều này chủ yếu nhằm tránh các ngoại lệ con trỏ rỗng.
Rust không có tính năng null mà nhiều ngôn ngữ khác có. Vấn đề với các giá trị null là nếu bạn cố gắng sử dụng một giá trị null như một giá trị không-null, bạn sẽ nhận được một số lỗi nào đó. Rust giải quyết vấn đề Null bằng cách giới thiệu kiểu enum Option. Tôi thấy thiết kế của Option thật tuyệt vời, kết hợp với match pattern matching, nó nghiêm ngặt hơn rất nhiều so với cách viết nullable type thêm dấu hỏi trong Kotlin.
Một enum đặc biệt hữu ích, gọi là
Option
, biểu diễn rằng một giá trị có thể là gì đó hoặc là không có gì cả. Định nghĩa của Option:
enum Option<T> {
None,
Some(T),
}
Hãy xem cách dùng match:
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
Sức mạnh của
match
đến từ khả năng biểu đạt của các mẫu (patterns) và thực tế là trình biên dịch đảm bảo rằng tất cả các trường hợp có thể xảy ra đều được xử lý. So sánh giữa match và if:
None
not covered"Như vậy, rõ ràng đoạn mã phân tích văn bản trên GitHub sử dụng enum một cách chuyên nghiệp hơn. Nó mang đậm phong cách của Rust...
Ghi chú: Option::None và Option::Some có thể viết tắt thành None / Some, vì hai kiểu này được tự động import.
Nếu có quá nhiều trường hợp enum và bạn không muốn xử lý hết, bạn có thể sử dụng other hoặc dấu gạch dưới để xử lý mặc định, tương tự như else.
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
other => move_player(other),
}
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
_ => (),
}
Sự khác biệt ở đây là other có thể lấy được giá trị tương ứng, trong khi dấu gạch dưới thì bỏ qua tất cả các giá trị. Ghi chú: Dấu ngoặc trống này tương tự Unit trong Kotlin, tức là void trong các ngôn ngữ khác.
Tuple không có giá trị nào có tên đặc biệt là unit. Giá trị này và kiểu dữ liệu tương ứng của nó đều được viết là
()
và biểu diễn một giá trị rỗng hoặc kiểu trả về rỗng. Các biểu thức sẽ tự động trả về giá trị unit nếu chúng không trả về bất kỳ giá trị nào khác. Cũng có một cách viết lười khác là if let, nó chỉ xử lý một trường hợp duy nhất được chỉ định sau let.
let config_max = Some(3u8);
if let Some(max) = config_max {
println!("Giá trị tối đa được cấu hình là {}", max);
}
Nó cũng hỗ trợ cú pháp else, giống như logic của dấu gạch dưới.
Tutorial "The Rust Programming Language" giảng dạy về enum một cách sâu sắc từ cơ bản đến nâng cao. Đáng là tài liệu chính thức được khuyến khích.