Menu
CoddyTech

Hàm thiết lập giá trị

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 12 trên 61.

Getter cho phép code bên ngoài đọc dữ liệu riêng tư. Nhưng nếu bạn cần cho phép chúng thay đổi dữ liệu thì sao? Đây là lúc phương thức setter phát huy tác dụng: những phương thức công khai giúp thay đổi các trường riêng tư một cách có kiểm soát.

Một phương thức setter cơ bản nhận &mut self và một giá trị mới:

// wallet.rs
pub struct Wallet {
    balance: f64,
}

impl Wallet {
    pub fn new(initial: f64) -> Wallet {
        Self { balance: initial }
    }
    
    pub fn balance(&self) -> f64 {
        self.balance
    }
    
    pub fn set_balance(&mut self, amount: f64) {
        self.balance = amount;
    }
}

Khác với phương thức lấy giá trị (getter), phương thức thiết lập giá trị (setter) trong Rust thường dùng tiền tố set_ để cho biết rõ rằng chúng thay đổi dữ liệu. Tham số &mut self rất quan trọng. Tham số này cho phép phương thức thay đổi các trường của struct.

Sức mạnh thực sự của các phương thức setter nằm ở khả năng kiểm tra tính hợp lệ. Thay vì chấp nhận mọi giá trị một cách mù quáng, bạn có thể áp dụng các quy tắc:

pub fn set_balance(&mut self, amount: f64) {
    if amount >= 0.0 {
        self.balance = amount;
    }
    // Các giá trị âm bị bỏ qua mà không có thông báo
}

Giờ đây, ví tự bảo vệ: dù code bên ngoài cố đặt giá trị nào, số dư cũng không thể âm. Đây là tính đóng gói đang hoạt động: struct tự kiểm soát các điều kiện bất biến của mình, còn code bên ngoài không thể khiến nó rơi vào trạng thái không hợp lệ.

challenge icon

Thử thách

Dễ

Hãy xây dựng một hệ thống bộ điều nhiệt để minh họa cách bộ thiết lập (setter) có thể áp dụng quy tắc nhằm giữ dữ liệu hợp lệ. Bộ điều nhiệt của bạn sẽ có cài đặt nhiệt độ chỉ có thể điều chỉnh trong một phạm vi an toàn.

Bạn sẽ tạo hai tệp để sắp xếp code:

  • thermostat.rs: Định nghĩa một struct Thermostat có trường temperature riêng tư (i32). Struct này nên ở chế độ công khai, nhưng trường vẫn ở chế độ riêng tư để ngăn các giá trị không hợp lệ. Hãy triển khai:
    • Một hàm khởi tạo new nhận nhiệt độ ban đầu
    • Một hàm getter temperature trả về nhiệt độ hiện tại
    • Một bộ thiết lập set_temperature chỉ chấp nhận các giá trị từ 10 đến 30 (bao gồm cả hai đầu). Nếu giá trị nằm ngoài phạm vi này, nhiệt độ phải giữ nguyên.
  • main.rs: Đưa module bộ điều nhiệt vào, tạo một bộ điều nhiệt và minh họa việc xác thực của bộ thiết lập bằng cách thử đặt các nhiệt độ khác nhau, rồi in kết quả sau mỗi lần thử.

Bộ thiết lập nên âm thầm bỏ qua các giá trị không hợp lệ: không hiển thị thông báo lỗi, chỉ giữ nguyên nhiệt độ hiện tại khi có người thử đặt nhiệt độ nằm ngoài phạm vi hợp lệ.

Đầu ra của bạn phải theo đúng định dạng này:

Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}

Ví dụ, nếu bạn tạo một bộ điều nhiệt ở mức 20, rồi thử đặt thành 25 (hợp lệ) và sau đó là 50 (không hợp lệ), đầu ra sẽ là:

Initial: 20
After setting to 25: 25
After setting to 50: 25

Bạn sẽ nhận ba đầu vào: nhiệt độ ban đầu, nhiệt độ thứ nhất cần thử đặt và nhiệt độ thứ hai cần thử đặt.

Tự làm thử

mod thermostat;

use thermostat::Thermostat;

fn main() {
    // Đọc các giá trị đầu vào
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let initial_temp: i32 = input1.trim().parse().expect("Invalid number");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let first_attempt: i32 = input2.trim().parse().expect("Invalid number");

    let mut input3 = String::new();
    std::io::stdin().read_line(&mut input3).expect("Failed to read line");
    let second_attempt: i32 = input3.trim().parse().expect("Invalid number");

    // TODO: Tạo một bộ điều nhiệt với nhiệt độ ban đầu

    // TODO: In ra nhiệt độ ban đầu
    // Định dạng: "Initial: {temperature}"

    // TODO: Thử đặt nhiệt độ lần thứ nhất và in ra kết quả
    // Định dạng: "After setting to {attempted_value}: {temperature}"

    // TODO: Thử đặt nhiệt độ lần thứ hai và in ra kết quả
    // Định dạng: "After setting to {attempted_value}: {temperature}"
}
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