Menu
CoddyTech

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.

challenge icon

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ên Container<T> với một trường (field) công khai duy nhất là item thuộc kiểu T. 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:

  1. 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
  2. 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
  3. 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: hello

Hã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}
}
quiz iconTự kiểm tra

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

Tự luyện tập: Trình biên dịch Rust online