Xem lại enum Option
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 17 trên 61.
Bạn đã gặp Option<T> trong Rust: đây là enum tiêu chuẩn dùng để biểu diễn các giá trị có thể tồn tại hoặc không. Bây giờ, hãy cùng nhìn nhận nó theo góc độ OOP: Option không chỉ là một enum, mà còn là một kiểu có các phương thức tích hợp mạnh mẽ, giúp bạn xử lý các giá trị có thể là null một cách an toàn và gọn gàng.
Thay vì kiểm tra mỗi lần, bạn có thể dùng trực tiếp các phương thức trên giá trị Option. Phương thức unwrap_or trả về giá trị bên trong nếu có, hoặc giá trị mặc định mà bạn cung cấp:
let maybe_name: Option<String> = Some(String::from("Alice"));
let name = maybe_name.unwrap_or(String::from("Guest"));
println!("{}", name); // Alice
let empty: Option<String> = None;
let fallback = empty.unwrap_or(String::from("Guest"));
println!("{}", fallback); // Guest
Phương thức map biến đổi giá trị bên trong nếu giá trị đó tồn tại, còn None thì giữ nguyên. Nhờ vậy, bạn có thể nối chuỗi các thao tác mà không phải liên tục kiểm tra None:
let maybe_num: Option<i32> = Some(5);
let doubled = maybe_num.map(|x| x * 2);
println!("{:?}", doubled); // Some(10)
let nothing: Option<i32> = None;
let still_nothing = nothing.map(|x| x * 2);
println!("{:?}", still_nothing); // None
Các phương thức này thể hiện những nguyên tắc của OOP: kiểu Option đóng gói khái niệm “có thể có một giá trị” và cung cấp một giao diện rõ ràng để làm việc với nó. Bạn gọi phương thức trên đối tượng thay vì viết logic bên ngoài để kiểm tra đối tượng.
Thử thách
DễHãy xây dựng một hệ thống hồ sơ người dùng xử lý dữ liệu tùy chọn một cách linh hoạt bằng các phương thức của Option. Người dùng có thể đã đặt biệt danh hoặc chưa. Hệ thống của bạn sẽ xử lý cả hai trường hợp một cách phù hợp mà không cần đối sánh tường minh.
Bạn sẽ tạo hai tệp để sắp xếp code:
profile.rs: Định nghĩa một struct công khaiProfilevới hai trường:username(String) vànickname(Option<String>). Triển khai:- Một hàm khởi tạo
newnhận tên người dùng và một biệt danh tùy chọn - Một phương thức
display_nametrả về biệt danh nếu có, hoặc dùng tên người dùng làm giá trị dự phòng: sử dụngunwrap_orđể xử lý việc này - Một phương thức
formatted_nicknametrả về mộtOption<String>với biệt danh được đặt trong dấu ngoặc vuông (như"[CoolNick]") nếu có, hoặcNonenếu không có biệt danh: sử dụngmapđể biến đổi giá trị
- Một hàm khởi tạo
main.rs: Đưa module hồ sơ vào và tạo hai hồ sơ: một hồ sơ có biệt danh và một hồ sơ không có biệt danh. Minh họa cả hai phương thức trên mỗi hồ sơ để cho thấy các phương thức củaOptionxử lý giá trị có mặt và vắng mặt khác nhau như thế nào.
Với phương thức formatted_nickname, hãy dùng định dạng debug ({:?}) khi in ra vì phương thức này trả về một Option.
Đầu ra của bạn phải theo đúng định dạng này, hiển thị cả hai hồ sơ:
Display name: {name}
Formatted nickname: {option}
Display name: {name}
Formatted nickname: {option}Ví dụ, với một hồ sơ có tên người dùng "alice" và biệt danh "Ace", cùng một hồ sơ khác có tên người dùng "bob" nhưng không có biệt danh, đầu ra sẽ là:
Display name: Ace
Formatted nickname: Some("[Ace]")
Display name: bob
Formatted nickname: NoneBạn sẽ nhận ba đầu vào: tên người dùng thứ nhất, biệt danh của người dùng thứ nhất và tên người dùng thứ hai (người không có biệt danh).
Tự làm thử
mod profile;
use profile::Profile;
fn main() {
// Đọc các đầu vào
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let username1 = input1.trim().to_string();
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let nickname1 = input2.trim().to_string();
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let username2 = input3.trim().to_string();
// TODO: Tạo hồ sơ đầu tiên với username1 và nickname1 (Some)
// TODO: Tạo hồ sơ thứ hai với username2 và không có biệt danh (None)
// TODO: In ra display_name và formatted_nickname của hồ sơ đầu tiên
// Dùng {:?} cho formatted_nickname vì phương thức này trả về một Option
// TODO: In ra display_name và formatted_nickname của hồ sơ thứ hai
}
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