Trait Display
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 36 trên 61.
Debug rất hữu ích cho các nhà phát triển khi kiểm tra dữ liệu, còn trait Display được thiết kế để hiển thị nội dung cho người dùng. Trait này cung cấp bộ định dạng {} trong println!. Khác với Debug, Rust không thể tự động suy ra Display. Bạn phải tự triển khai trait này.
Để triển khai Display, bạn cần thêm mô-đun fmt và triển khai phương thức fmt:
use std::fmt;
struct Temperature {
celsius: f64,
}
impl fmt::Display for Temperature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}°C", self.celsius)
}
}
Phương thức (method) fmt nhận một Formatter và trả về fmt::Result. Bạn dùng macro write! để định dạng đầu ra, truy cập các trường của cấu trúc thông qua self.
Bây giờ bạn có thể in struct bằng bộ định dạng {} tiêu chuẩn:
let temp = Temperature { celsius: 23.5 };
println!("{}", temp); // 23.5°C
Điểm khác biệt chính: đầu ra Debug cho thấy cấu trúc dữ liệu của bạn, hữu ích khi gỡ lỗi, còn đầu ra Display được trình bày chỉn chu và dành cho người dùng cuối. Một struct có thể triển khai cả hai: dùng {:?} để gỡ lỗi và {} để tạo đầu ra gọn gàng.
Thử thách
DễHãy tạo một hệ thống hiển thị sản phẩm thân thiện với người dùng! Trong khi Debug hiển thị cấu trúc dữ liệu thô, trait Display cho phép bạn tạo đầu ra chỉn chu, dễ đọc, phù hợp với người dùng cuối.
Bạn sẽ sắp xếp code trong hai tệp:
product.rs: Định nghĩa một structProductcông khai với hai trường công khai:name(String) vàprice(f64). Triển khai traitDisplaycho struct để định dạng theo mẫu{name} - ${price}. Nhớ đưastd::fmtvào và dùng macrowrite!bên trong phương thứcfmt.main.rs: Đưa module product vào và tạo một instanceProductbằng các đầu vào được cung cấp. In sản phẩm bằng bộ định dạng{}tiêu chuẩn để hiển thị kết quả tùy chỉnh.
Trait Display yêu cầu bạn tự triển khai phương thức fmt: Rust không thể tự động suy diễn phương thức này như Debug. Nhờ vậy, bạn có toàn quyền kiểm soát cách kiểu dữ liệu của mình hiển thị với người dùng.
Đầu ra của bạn cần hiển thị sản phẩm theo định dạng gọn gàng, thân thiện với người dùng:
{name} - ${price}Ví dụ, với đầu vào Wireless Mouse và 29.99:
Wireless Mouse - $29.99Bạn sẽ nhận hai đầu vào: tên sản phẩm và giá (phân tích thành kiểu f64).
Tự làm thử
mod product;
use product::Product;
fn main() {
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
let mut price_input = String::new();
std::io::stdin().read_line(&mut price_input).expect("Failed to read line");
let price: f64 = price_input.trim().parse().expect("Failed to parse price");
// TODO: Tạo một instance Product với tên và giá
// TODO: In sản phẩm ra bằng bộ định dạ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