Phương thức tổng quát
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 25 trên 61.
Một struct generic có thể chứa bất kỳ kiểu nào, nhưng sẽ không hữu ích lắm nếu thiếu các phương thức để thao tác với dữ liệu bên trong. Để định nghĩa phương thức cho struct generic, bạn cần dùng cú pháp đặc biệt trong khối impl.
Điểm mấu chốt là khai báo tham số tổng quát trên chính impl:
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
fn get(&self) -> &T {
&self.value
}
}
Hãy chú ý đến impl<T> đứng trước Wrapper<T>. Điều này cho Rust biết rằng T là tham số kiểu tổng quát (generic type parameter) cho toàn bộ khối triển khai. Nếu không có khai báo này, Rust sẽ tìm một kiểu cụ thể tên là T và không tìm thấy.
Phương thức get trả về &T: một tham chiếu đến bất kỳ kiểu dữ liệu nào mà trình bao bọc chứa. Cách này hoạt động dù T là số nguyên, chuỗi hay bất kỳ kiểu dữ liệu nào khác:
let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };
println!("{}", num_wrapper.get()); // 100
println!("{}", text_wrapper.get()); // Rust
Cùng một định nghĩa phương thức dùng được cho cả hai, vì kiểu tổng quát (generic) T thích ứng với từng kiểu cụ thể tại thời điểm biên dịch.
Thử thách
DễHãy mở rộng vùng chứa tổng quát của bạn bằng các phương thức (method)! Bạn sẽ xây dựng một cấu trúc Box (không nhầm với Box tiêu chuẩn của Rust), có thể chứa bất kỳ kiểu dữ liệu nào và cung cấp các phương thức để tương tác với nội dung bên trong.
Bạn sẽ sắp xếp code trong hai tệp:
mybox.rs: Định nghĩa một cấu trúc tổng quát công khai tên làMyBox<T>, với trường riêng tưcontentscó kiểuT. Triển khai các phương thức cho cấu trúc này:- Một hàm liên kết
newtạo mộtMyBoxmới với giá trị đã cho - Một phương thức
peektrả về tham chiếu đến nội dung bên trong (dùng&self) - Một phương thức
replacenhận giá trị mới và thay thế nội dung hiện tại (dùng&mut self)
- Một hàm liên kết
main.rs: Đưa module của bạn vào và minh họa cách các phương thức tổng quát hoạt động với những kiểu dữ liệu khác nhau. Bạn sẽ tạo các hộp, xem nội dung bên trong và thay thế giá trị để minh họa cách các phương thức hoạt động.
Hãy nhớ cú pháp quan trọng để triển khai phương thức trên một cấu trúc tổng quát: bạn cần viết impl<T> trước MyBox<T> để cho Rust biết rằng T là tham số tổng quát cho toàn bộ khối triển khai.
Trong tệp chính, hãy minh họa MyBox bằng cách:
- Tạo một hộp chứa số nguyên (đầu vào thứ nhất, được phân tích thành
i32) - Xem nội dung bên trong và in giá trị ra
- Thay thế nội dung bằng một số nguyên mới (đầu vào thứ hai, được phân tích thành
i32) - Xem lại nội dung để hiển thị giá trị đã cập nhật
- Tạo hộp thứ hai chứa chuỗi (đầu vào thứ ba)
- Xem nội dung bên trong hộp chứa chuỗi
Đầu ra của bạn phải theo định dạng sau:
Integer box contains: {value}
After replace: {value}
String box contains: {value}Ví dụ, với các đầu vào 10, 25 và Rust:
Integer box contains: 10
After replace: 25
String box contains: RustBạn sẽ nhận ba đầu vào: một số nguyên ban đầu, một số nguyên thay thế và một giá trị chuỗi.
Tự làm thử
mod mybox;
use mybox::MyBox;
fn main() {
// Đọc dữ liệu đầu vào
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_int: i32 = input1.trim().parse().expect("Invalid integer");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let string_value = input3.trim().to_string();
// TODO: Tạo một MyBox chứa số nguyên ban đầu
// TODO: Xem nội dung của nó và in ra: "Integer box contains: {value}"
// TODO: Thay nội dung bằng số nguyên thay thế
// TODO: Xem lại và in ra: "After replace: {value}"
// TODO: Tạo MyBox thứ hai chứa giá trị chuỗi
// TODO: Xem nội dung của hộp chuỗi và in ra: "String box contains: {value}"
}
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