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ệ.
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 structThermostatcó trườngtemperatureriê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
newnhận nhiệt độ ban đầu - Một hàm getter
temperaturetrả về nhiệt độ hiện tại - Một bộ thiết lập
set_temperaturechỉ 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.
- Một hàm khởi tạo
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: 25Bạ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}"
}
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