Triển khai trait
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 30 trên 61.
Bây giờ bạn đã biết cách định nghĩa một trait, hãy cùng xem cách để một struct đáp ứng hợp đồng đó. Việc triển khai trait kết nối yêu cầu trừu tượng với hành vi cụ thể.
Cú pháp sử dụng impl TraitName for StructName:
trait Speak {
fn speak(&self) -> String;
}
struct Dog {
name: String,
}
impl Speak for Dog {
fn speak(&self) -> String {
format!("{} says: Woof!", self.name)
}
}
Khối impl Speak for Dog cho Rust biết rằng Dog đang triển khai trait Speak. Bên trong, bạn viết phần thân phương thức thực tế. Đây là nơi bạn định nghĩa chó nói như thế nào.
Sức mạnh của các trait sẽ trở nên rõ ràng khi nhiều kiểu cùng triển khai một trait:
struct Cat {
name: String,
}
impl Speak for Cat {
fn speak(&self) -> String {
format!("{} says: Meow!", self.name)
}
}
Cả Dog và Cat giờ đều có khả năng Speak, nhưng mỗi kiểu lại có cách triển khai riêng. Bạn có thể gọi .speak() trên một trong hai kiểu:
let dog = Dog { name: String::from("Rex") };
let cat = Cat { name: String::from("Whiskers") };
println!("{}", dog.speak()); // Rex kêu: Woof!
println!("{}", cat.speak()); // Whiskers kêu: Meow!
Đây là nền tảng của tính đa hình trong Rust: các kiểu dữ liệu khác nhau, cùng một giao diện, hành vi riêng biệt.
Thử thách
DễHãy làm cho trait trở nên hữu ích bằng cách triển khai chúng cho các kiểu khác nhau! Bạn sẽ tạo một trait Describable và triển khai trait này cho hai struct khác nhau, mỗi struct cung cấp một mô tả riêng.
Bạn sẽ sắp xếp code trong ba tệp:
describable.rs: Định nghĩa một trait công khaiDescribablevới phương thứcdescribe(&self) -> String.items.rs: Tạo hai struct công khai triển khai trait của bạn:Bookcó trườngtitlecông khai (String)Moviecó trườngnamecông khai (String)
Describablevới định dạng mô tả riêng.main.rs: Kết hợp các module, tạo instance của cả hai struct, rồi gọi phương thứcdescribeđể cho thấy cùng một trait tạo ra đầu ra khác nhau cho các kiểu khác nhau.
Book cần tự mô tả là Book: {title} và Movie cần tự mô tả là Film: {name}. Hãy chú ý cách mỗi kiểu đáp ứng cùng một giao ước nhưng có hành vi riêng!
Trong tệp chính, hãy tạo một cuốn sách và một bộ phim bằng hai đầu vào đã cho, sau đó in mô tả của chúng trên các dòng riêng biệt.
Đầu ra của bạn cần theo định dạng này:
Book: {title}
Film: {name}Ví dụ, với đầu vào 1984 và Inception:
Book: 1984
Film: InceptionBạn sẽ nhận hai đầu vào: tên sách và tên phim.
Tự làm thử
mod describable;
mod items;
use describable::Describable;
use items::{Book, Movie};
fn main() {
// Đọc dữ liệu đầu vào
let mut title = String::new();
std::io::stdin().read_line(&mut title).expect("Failed to read line");
let title = title.trim().to_string();
let mut name = String::new();
std::io::stdin().read_line(&mut name).expect("Failed to read line");
let name = name.trim().to_string();
// TODO: Tạo một instance Book với title
// TODO: Tạo một instance Movie với name
// TODO: In ra mô tả của cuốn sách
// TODO: In ra mô tả của bộ phim
}
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