Cách triển khai mặc định
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 31 trên 61.
Cho đến nay, mọi phương thức trait mà ta định nghĩa đều chỉ có chữ ký: một yêu cầu không có phần thân. Nhưng nếu hầu hết các kiểu dữ liệu triển khai trait đều dùng cùng một logic thì sao? Rust cho phép bạn cung cấp phần triển khai mặc định ngay trong định nghĩa trait.
Thay vì kết thúc chữ ký phương thức bằng dấu chấm phẩy, bạn thêm phần thân:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
Giờ đây, bất kỳ kiểu nào triển khai Greet đều tự động có phương thức này mà không cần viết code nào trong khối impl:
struct Guest;
impl Greet for Guest {}
let visitor = Guest;
println!("{}", visitor.greet()); // Xin chào!
impl Greet for Guest {} trống vẫn hợp lệ vì trait đã cung cấp hành vi. Struct chỉ cần «đăng ký» dùng trait và được nhận phương thức mặc định miễn phí.
Mẫu này hữu ích khi bạn muốn định nghĩa hành vi chung phù hợp với hầu hết các trường hợp. Các kiểu cần hành vi khác có thể ghi đè hành vi mặc định (bạn sẽ học điều này tiếp theo), còn những kiểu hài lòng với hành vi tiêu chuẩn thì không cần lặp lại.
Thử thách
DễHãy cùng khám phá sức mạnh của các phần triển khai mặc định bằng cách xây dựng một hệ thống thông báo! Bạn sẽ tạo một trait cung cấp hành vi tiêu chuẩn ngay từ đầu, để các kiểu có thể sử dụng mà không cần viết code lặp lại.
Bạn sẽ sắp xếp code trong ba tệp:
notifiable.rs: Định nghĩa một trait công khaiNotifiablevới phương thứcnotify(&self) -> Stringcó phần triển khai mặc định. Phần mặc định này sẽ trả về"You have a new notification!". Mọi kiểu triển khai trait này sẽ tự động có hành vi đó mà không cần viết gì trong khối impl.alerts.rs: Tạo hai unit struct công khai đơn giản triển khai trait của bạn:EmailAlert: triển khaiNotifiablebằng một khối impl trống (sử dụng phần mặc định)SystemAlert: cũng triển khaiNotifiablebằng một khối impl trống (sử dụng phần mặc định)
main.rs: Kết hợp các module và minh họa cách cả hai kiểu cảnh báo dùng chung hành vi mặc định. Tạo instance của cả hai struct và gọi các phương thứcnotifycủa chúng.
Trong tệp chính, hãy tạo một EmailAlert và một SystemAlert, sau đó in thông báo của chúng trên các dòng riêng biệt.
Đầu ra của bạn sẽ là:
You have a new notification!
You have a new notification!Hãy chú ý cách cả hai kiểu tạo ra đầu ra giống hệt nhau: đó là điểm hay của các phần triển khai mặc định! Không struct nào cần viết code cho phương thức notify, vậy mà cả hai đều có hành vi thông báo hoạt động đầy đủ. Trong bài học tiếp theo, bạn sẽ học cách ghi đè các giá trị mặc định này khi một kiểu cần hành vi tùy chỉnh.
Tự làm thử
mod notifiable;
mod alerts;
use notifiable::Notifiable;
use alerts::{EmailAlert, SystemAlert};
fn main() {
// TODO: Tạo một instance của EmailAlert
// TODO: Tạo một instance của SystemAlert
// TODO: In ra thông báo từ EmailAlert
// TODO: In ra thông báo từ SystemAlert
}
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 độ3Enum nâng cao
Enum có dữ liệuPhương thức của enumKhớp các biến thể dữ liệuXem lại enum OptionÔn tập: enum Shape6Định nghĩa trait
Trait là gì?Triển khai traitCách triển khai mặc địnhGhi đè cách triển khai mặc địnhTrait có tham sốÔn tập: trình phát đa phương tiệnTự luyện tập: Trình biên dịch Rust online