Сеттеры
Часть раздела Объектно-ориентированное программирование путешествия по Rust на Coddy. Урок 12 из 61.
Getter-методы позволяют внешнему коду read private-данные. Но что, если нужно позволить ему их изменять? Здесь на помощь приходят методы setter: public-методы, которые контролируемым образом изменяют private-поля.
Базовый setter принимает &mut self и новое значение:
// 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;
}
}
В отличие от getter, setter в Rust обычно используют префикс set_, чтобы ясно указать, что они изменяют данные. Параметр &mut self необходим. Он даёт методу разрешение изменять поля структуры.
Настоящая сила setter заключается в проверке. Вместо того чтобы бездумно принимать любое значение, вы можете применять правила:
pub fn set_balance(&mut self, amount: f64) {
if amount >= 0.0 {
self.balance = amount;
}
// Отрицательные значения молча игнорируются
}
Теперь кошелёк защищает себя: какое бы значение внешний код ни попытался установить, balance никогда не может стать отрицательным. Это инкапсуляция в действии: структура контролирует собственные инварианты, и внешний код просто не может привести её в недопустимое состояние.
Задание
ЛегкоСоздадим систему термостата, демонстрирующую, как setter могут обеспечивать соблюдение правил для поддержания данных в допустимом состоянии. У вашего термостата будет настройка температуры, которую можно изменять только в безопасном диапазоне.
Вы создадите два файла, чтобы организовать код:
thermostat.rs: Define структуруThermostatс private полемtemperature(i32). Структура должна быть public, но поле остаётся private, чтобы защитить его от недопустимых значений. Implement:- конструктор
new, принимающий initial температуру - getter
temperature, который возвращает current температуру - setter
set_temperature, который принимает только значения between 10 и 30 (inclusive). Если значение находится outside этого диапазона, температура должна остаться без изменений.
- конструктор
main.rs: Подключите модуль термостата, создайте термостат и продемонстрируйте проверку setter, пытаясь установить различные температуры и выводя result после каждой Attempt.
setter должен молча игнорировать недопустимые значения: никаких сообщений об ошибках — просто keep current температуру без изменений, когда кто-либо пытается установить её outside допустимого диапазона.
Ваш вывод должен точно соответствовать следующему формату:
Initial: {temperature}
After setting to {attempted_value}: {temperature}
After setting to {attempted_value}: {temperature}Например, если вы создадите термостат с температурой 20, затем попытаетесь установить её на 25 (допустимое значение), а затем на 50 (недопустимое значение), вывод будет таким:
Initial: 20
After setting to 25: 25
After setting to 50: 25Вы получите три входных значения: initial температуру, первую температуру для Attempt и вторую температуру для Attempt.
Попробуйте сами
mod thermostat;
use thermostat::Thermostat;
fn main() {
// Считать входные данные
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: Создать термостат с начальной температурой
// TODO: Вывести начальную температуру
// Формат: "Initial: {temperature}"
// TODO: Попытаться установить первую температуру и вывести результат
// Format: "After setting to {attempted_value}: {temperature}"
// TODO: Попытаться установить вторую температуру и вывести результат
// Format: "After setting to {attempted_value}: {temperature}"
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Методы и поведение
Введение в блоки реализацииПараметр SelfИзменяемые методыАссоциированные функцииНесколько блоков реализацииЦепочки вызовов методовИтоги: действия с Rectangle4Проект: Виртуальный питомец
Определение питомцаКормление питомца2Инкапсуляция и модули
Основы модулейКлючевое слово PublicПриватные поляГеттерыСеттерыИтоги — Безопасный сейф5Обобщения
Обобщённые структурыОбобщённые методыНесколько обобщённых типовОбобщённые функцииПовторение — Координатная точка8Трейты как ограничения
Синтаксис ограничений трейтовМножественные ограниченияКонструкция whereВозврат типов с трейтамиИтоги — Обобщённый принтер11Паттерны проектирования в Rust
Паттерн NewtypeКомпозицияТрейт DropFrom и IntoИтоги — Мок-объект Smart Pointer3Продвинутые перечисления
Перечисления с даннымиМетоды в перечисленияхСопоставление вариантов с даннымиСнова об Option EnumИтоги — перечисление Shape6Определение трейтов
Что такое трейт?Реализация трейтовРеализации по умолчаниюПереопределение реализаций по умолчаниюТрейты с параметрамиИтоги — Media PlayerПотренируйтесь самостоятельно: Онлайн-компилятор Rust