Mệnh đề where
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 42 trên 61.
Khi thêm nhiều trait bound, chữ ký hàm có thể trở nên khó đọc. Hãy xem xét một hàm có nhiều tham số tổng quát, mỗi tham số cần nhiều trait:
fn complex_operation<T: Display + Clone, U: Debug + Summary>(first: T, second: U) {
// ...
}
Cách này hiệu quả, nhưng phần khai báo hàm đang trở nên rườm rà. Mệnh đề where là một lựa chọn gọn gàng hơn, giúp chuyển các ràng buộc trait xuống sau danh sách tham số:
fn complex_operation<T, U>(first: T, second: U)
where
T: Display + Clone,
U: Debug + Summary,
{
// ...
}
Cả hai phiên bản có chức năng giống hệt nhau: mệnh đề where chỉ giúp câu lệnh dễ đọc hơn. Các yêu cầu của từng kiểu dữ liệu được viết trên một dòng riêng, giúp bạn dễ xem từng tham số tổng quát cần gì.
Mệnh đề where đặc biệt hữu ích khi các ràng buộc phức tạp hoặc khi bạn có nhiều tham số tổng quát. Mệnh đề này giúp bạn dễ dàng thấy tên hàm và các tham số, còn các ràng buộc được liệt kê riêng bên dưới. Đây là phong cách được ưu tiên trong hầu hết các codebase Rust khi các ràng buộc phức tạp hơn T: Trait đơn giản.
Thử thách
DễHãy xây dựng một hệ thống xử lý dữ liệu dùng mệnh đề where để giúp các ràng buộc trait phức tạp dễ đọc hơn! Bạn sẽ tạo một hàm tổng quát có nhiều tham số kiểu, mỗi tham số yêu cầu các trait khác nhau, rồi sắp xếp các ràng buộc rõ ràng bằng cú pháp where.
Bạn sẽ chia code thành hai tệp:
processor.rs: Định nghĩa hai trait công khai và một hàm tổng quát dùng cả hai:Summarize: một trait có phương thứcsummary, nhận&selfvà trả vềStringValidate: một trait có phương thứcvalidate, nhận&selfvà trả vềbool
process_items, nhận hai tham số thuộc các kiểu tổng quát khác nhau. Dùng mệnh đềwheređể quy định rằng kiểu thứ nhất phải triển khai cảClonevàSummarize, còn kiểu thứ hai phải triển khaiValidate. Hàm cần in ra phần tóm tắt của phần tử thứ nhất, rồi in ra phần tử thứ hai có hợp lệ hay không.main.rs: Tạo hai cấu trúc công khai triển khai các trait cần thiết:Article: có trườngtitlecông khai (String). Triển khaiSummarizeđể trả vềArticle: {title}, và dẫn xuấtClone.Form: có trườngfilledcông khai (bool). Triển khaiValidateđể trả về giá trị củafilled.
process_itemsvới cả hai.
Mệnh đề where giúp chữ ký hàm gọn gàng hơn nhiều so với việc nhồi tất cả ràng buộc vào dấu ngoặc nhọn. Yêu cầu của từng kiểu nằm trên một dòng riêng, giúp bạn dễ thấy mỗi tham số tổng quát cần gì.
Đầu ra cần hiển thị phần tóm tắt, sau đó là kết quả xác thực:
Article: {title}
Valid: {true/false}Ví dụ, với đầu vào Rust Tips và true:
Article: Rust Tips
Valid: trueVà với đầu vào Breaking News và false:
Article: Breaking News
Valid: falseBạn sẽ nhận hai đầu vào: tiêu đề bài viết và thông tin biểu mẫu đã được điền hay chưa (phân tích thành bool).
Tự làm thử
mod processor;
use processor::{Summarize, Validate, process_items};
use std::io;
// TODO: Định nghĩa một struct public Article với trường title public (String)
// Thêm derive Clone cho Article
// TODO: Triển khai Summarize cho Article
// Phương thức summary cần trả về "Article: {title}"
// TODO: Định nghĩa một struct public Form với trường filled public (bool)
// TODO: Triển khai Validate cho Form
// Phương thức validate cần trả về giá trị của filled
fn main() {
let mut title = String::new();
io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut filled_input = String::new();
io::stdin().read_line(&mut filled_input).expect("Failed to read line");
let filled: bool = filled_input.trim().parse().expect("Failed to parse bool");
// TODO: Tạo một Article với title đã cho
// TODO: Tạo một Form với giá trị filled đã cho
// TODO: Gọi process_items với article và form
}
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 độ8Trait làm ràng buộc
Cú pháp ràng buộc traitNhiều ràng buộcMệnh đề whereTrả về kiểu có traitÔn tập: hàm in tổng quátTự luyện tập: Trình biên dịch Rust online