Cấu trú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 24 trên 61.
Đến giờ, mọi struct bạn tạo đều có các trường với kiểu cụ thể. Một Pet có tên kiểu String, một Rectangle có các kích thước kiểu f64. Nhưng nếu bạn muốn tạo một struct có thể chứa bất kỳ kiểu dữ liệu nào thì sao?
Đây là lúc kiểu tổng quát phát huy tác dụng. Kiểu tổng quát cho phép bạn viết code linh hoạt, có thể tái sử dụng và hoạt động với nhiều kiểu dữ liệu. Thay vì cố định một kiểu dữ liệu cụ thể, bạn dùng một kiểu giữ chỗ, thường là T, rồi kiểu này sẽ được thay bằng kiểu dữ liệu cụ thể khi bạn dùng cấu trúc.
Đây là một struct bao bọc đơn giản có thể chứa bất kỳ kiểu dữ liệu nào:
struct Wrapper<T> {
value: T,
}
<T> sau tên struct khai báo một tham số kiểu tổng quát. Bên trong struct, T đóng vai trò thay thế cho kiểu dữ liệu bạn sẽ dùng. Khi tạo một instance, Rust suy luận kiểu cụ thể:
let int_wrapper = Wrapper { value: 42 }; // T là i32
let float_wrapper = Wrapper { value: 3.14 }; // T là f64
let text_wrapper = Wrapper { value: "hello" }; // T là &str
Mỗi kiểu trong số này là một kiểu cụ thể khác nhau, Wrapper<i32>, Wrapper<f64> và Wrapper<&str>, nhưng tất cả đều dùng chung một định nghĩa struct. Nhờ đó, bạn không cần viết các struct riêng biệt như IntWrapper, FloatWrapper và StringWrapper để thực hiện những việc về cơ bản giống nhau.
Ký tự T chỉ là quy ước (viết tắt của “Type”). Bạn có thể dùng bất kỳ định danh hợp lệ nào, nhưng T là cách dùng phổ biến trong Rust và hầu hết các ngôn ngữ khác hỗ trợ kiểu tổng quát.
Thử thách
DễHãy tạo một vùng chứa tổng quát có thể chứa giá trị thuộc bất kỳ kiểu dữ liệu nào! Bạn sẽ tạo một cấu trúc Container để minh họa cách kiểu tổng quát giúp đoạn code linh hoạt và có thể tái sử dụng.
Bạn sẽ sắp xếp đoạn code trong hai tệp:
container.rs: Định nghĩa một cấu trúc tổng quát công khai có tênContainer<T>với một trường (field) công khai duy nhất làitemthuộc kiểuT. Vùng chứa này có thể chứa mọi kiểu dữ liệu: số nguyên, số thực, chuỗi hoặc bất kỳ kiểu nào khác.main.rs: Đưa module vùng chứa vào và minh họa tính linh hoạt của nó bằng cách tạo các vùng chứa chứa nhiều kiểu dữ liệu khác nhau. Bạn sẽ tạo ba vùng chứa và hiển thị nội dung của từng vùng.
Trong tệp chính, hãy tạo các vùng chứa sau:
- Một vùng chứa chứa giá trị số nguyên (integer), tức đầu vào thứ nhất, được phân tích thành
i32 - Một vùng chứa chứa giá trị số thực (float), tức đầu vào thứ hai, được phân tích thành
f64 - Một vùng chứa chứa chuỗi (string), tức đầu vào thứ ba, được giữ dưới dạng
String
Đầu ra cần hiển thị nội dung của từng vùng chứa theo định dạng sau:
Integer container: {value}
Float container: {value}
String container: {value}Ví dụ, với các đầu vào 42, 3.14 và hello:
Integer container: 42
Float container: 3.14
String container: helloHãy lưu ý rằng cùng một định nghĩa Container<T> hoạt động với cả ba kiểu dữ liệu khác nhau: đó chính là sức mạnh của kiểu tổng quát!
Bạn sẽ nhận ba đầu vào: một giá trị số nguyên, một giá trị số thực và một giá trị chuỗi.
Tự làm thử
mod container;
use container::Container;
fn main() {
// Đọc ba đầu vào
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let int_value: i32 = input1.trim().parse().expect("Failed to parse integer");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let float_value: f64 = input2.trim().parse().expect("Failed to parse float");
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 ba container bằng Container<T>
// 1. Một container chứa số nguyên int_value
// 2. Một container chứa số thực float_value
// 3. Một container chứa chuỗi string_value
// TODO: In nội dung của từng container theo định dạng yêu cầu
// Integer container: {value}
// Float container: {value}
// String container: {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