Enum có dữ liệu
Thuộc phần Lập trình hướng đối tượng trong hành trình Rust của Coddy. Bài học 14 trên 61.
Enum cơ bản (enum) trong Rust cho phép bạn định nghĩa một kiểu dữ liệu với tập hợp biến thể cố định, như Direction::North hoặc Status::Active. Nhưng enum trong Rust còn mạnh hơn thế nhiều. Mỗi biến thể có thể chứa dữ liệu riêng, giúp enum cực kỳ linh hoạt khi mô hình hóa các tình huống thực tế.
Hãy hình dung một hệ thống nhắn tin, trong đó mỗi loại tin nhắn mang thông tin khác nhau. Tin nhắn văn bản có nội dung, lệnh di chuyển có tọa độ, còn tín hiệu thoát thì không chứa gì cả. Trong Rust, bạn có thể biểu diễn tất cả những loại này bằng một enum duy nhất:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
Mỗi biến thể có hình dạng khác nhau. Quit không chứa dữ liệu: nó chỉ là một tín hiệu.
Move dùng cú pháp dạng struct với các trường được đặt tên. Write chứa một String duy nhất theo cú pháp tuple. ChangeColor chứa ba giá trị biểu thị các thành phần RGB.
Cách tạo đối tượng của các biến thể này như sau:
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);
Điểm hay của cách tiếp cận này là m1, m2, m3 và m4 đều có cùng kiểu dữ liệu: Message. Bạn có thể lưu chúng trong cùng một tập hợp, truyền chúng vào cùng một hàm hoặc trả về bất kỳ biến thể nào từ một hàm duy nhất. Enum hợp nhất các cấu trúc dữ liệu khác nhau dưới cùng một kiểu dữ liệu mà vẫn giữ nguyên thông tin riêng cần thiết cho từng biến thể.
Thử thách
DễHãy xây dựng một hệ thống thông báo dùng enum có dữ liệu để biểu thị các loại cảnh báo khác nhau. Mỗi loại thông báo mang thông tin khác nhau: một số có thông điệp, một số có giá trị số, còn một số chỉ là tín hiệu đơn giản.
Bạn sẽ tạo hai tệp để sắp xếp code:
notification.rs: Định nghĩa một enumNotificationcông khai với ba biến thể:Alert: chứa một thông điệpString(cú pháp tuple)Reminder: chứa các trường có tên:title(String) vàminutes(u32)Dismiss: không chứa dữ liệu, chỉ là một tín hiệu
main.rs: Đưa module thông báo vào và tạo một đối tượng cho mỗi biến thể. Sau đó, in thông tin về từng thông báo để cho thấy cả ba biến thể đều cùng kiểu nhưng mang dữ liệu khác nhau.
Khi in, hãy dùng định dạng gỡ lỗi ({:?}) để hiển thị từng thông báo. Bạn cần dẫn xuất trait Debug cho enum để có thể in theo cách này.
Đầu ra của bạn cần hiển thị cả ba thông báo, mỗi thông báo trên một dòng riêng:
Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
DismissVí dụ, với thông điệp cảnh báo là "Server down", lời nhắc có tiêu đề "Meeting" và 30 phút, đầu ra sẽ là:
Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
DismissBạn sẽ nhận ba đầu vào: thông điệp cảnh báo, tiêu đề lời nhắc và số phút nhắc.
Tự làm thử
mod notification;
use notification::Notification;
fn main() {
// Đọc dữ liệu đầu vào
let mut alert_message = String::new();
std::io::stdin().read_line(&mut alert_message).expect("Failed to read line");
let alert_message = alert_message.trim().to_string();
let mut reminder_title = String::new();
std::io::stdin().read_line(&mut reminder_title).expect("Failed to read line");
let reminder_title = reminder_title.trim().to_string();
let mut minutes_input = String::new();
std::io::stdin().read_line(&mut minutes_input).expect("Failed to read line");
let reminder_minutes: u32 = minutes_input.trim().parse().expect("Failed to parse minutes");
// TODO: Tạo thông báo Alert bằng alert_message
// TODO: Tạo thông báo Reminder bằng reminder_title và reminder_minutes
// TODO: Tạo thông báo Dismiss
// TODO: In ra từng thông báo bằng định dạng gỡ lỗi {:?}
// In mỗi thông báo trên một dòng riêng
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiến độ.
Tất cả bài học trong Lập trình hướng đối tượng
1Phương thức và hành vi
Nhập môn khối triển khaiTham số selfPhương thức có thể thay đổiHàm liên kếtNhiều khối triển khaiNối chuỗi phương thứcÔn tập: thao tác với hình chữ nhật4Dự án: Thú cưng ảo
Định nghĩa thú cưngCho thú cưng ăn7Các trait tiêu chuẩn
Trait DebugTrait DisplayClone và CopyCác trait so sánh bằngÔn tập: Điểm có thể in ra2Tính đóng gói và module
Kiến thức cơ bản về moduleTừ khóa publicTrường riêng tưHàm lấy giá trịHàm thiết lập giá trịÔn tập: tủ khóa an toàn5Kiểu tổng quát
Cấu trúc tổng quátPhương thức tổng quátNhiều kiểu tổng quátHàm tổng quátÔn tập: điểm tọa độTự luyện tập: Trình biên dịch Rust online