Menu
Coddy logo textTech

Сеттеры

Часть раздела Object Oriented Programming путешествия по Rust на Coddy — урок 12 из 61.

Геттеры позволяют внешнему коду читать приватные данные. Но что, если вам нужно позволить ему изменять их? Здесь на помощь приходят методы-сеттеры — публичные методы, которые изменяют приватные поля контролируемым образом.

Базовый сеттер принимает &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;
    }
}

В отличие от геттеров, сеттеры в Rust обычно используют префикс set_, чтобы явно указать на изменение данных. Параметр &mut self необходим — он дает методу разрешение на изменение полей структуры.

Настоящая сила сеттеров заключается в валидации. Вместо того чтобы слепо принимать любое значение, вы можете применять правила:

pub fn set_balance(&mut self, amount: f64) {
    if amount >= 0.0 {
        self.balance = amount;
    }
    // Отрицательные значения молча игнорируются
}

Теперь кошелек защищает себя — какое бы значение ни пытался установить внешний код, баланс никогда не сможет стать отрицательным. Это инкапсуляция в действии: struct контролирует свои собственные инварианты, и внешний код просто не может привести её в недопустимое состояние.

challenge icon

Задание

Легко

Давайте создадим систему термостата, которая демонстрирует, как сеттеры могут применять правила для обеспечения валидности данных. Ваш термостат будет иметь настройку температуры, которую можно регулировать только в пределах безопасного диапазона.

Для организации кода вы создадите два файла:

  • thermostat.rs: Определите структуру Thermostat с приватным полем temperature (i32). Структура должна быть публичной, но поле остается приватным, чтобы защитить его от недопустимых значений. Реализуйте:
    • Конструктор new, который принимает начальную температуру
    • Геттер temperature, который возвращает текущую температуру
    • Сеттер set_temperature, который принимает только значения от 10 до 30 (включительно). Если значение находится вне этого диапазона, температура должна остаться неизменной.
  • main.rs: Подключите модуль термостата, создайте термостат и продемонстрируйте валидацию сеттера, пытаясь установить различные значения температуры и выводя результат после каждой попытки.

Сеттер должен молча игнорировать недопустимые значения — никаких сообщений об ошибках, просто сохраняйте текущую температуру без изменений, когда кто-то пытается установить её вне допустимого диапазона.

Ваш вывод должен соответствовать следующему формату:

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

Вы получите три входных значения: начальную температуру, первую попытку установки температуры и вторую попытку установки температуры.

Шпаргалка

Методы-сеттеры позволяют внешнему коду изменять приватные поля контролируемым образом. Они принимают &mut self, чтобы получить разрешение на изменение данных структуры.

Базовый синтаксис сеттера:

pub fn set_balance(&mut self, amount: f64) {
    self.balance = amount;
}

Сеттеры в Rust обычно используют префикс set_, чтобы четко указать, что они изменяют данные.

Сеттеры позволяют выполнять валидацию для обеспечения соблюдения правил и поддержания целостности данных:

pub fn set_balance(&mut self, amount: f64) {
    if amount >= 0.0 {
        self.balance = amount;
    }
    // Недопустимые значения молча игнорируются
}

Это инкапсуляция в действии: структура контролирует свои собственные инварианты, не позволяя внешнему коду перевести её в недопустимое состояние.

Попробуйте сами

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: Попробуйте установить первую температуру и выведите результат
    // Формат: "After setting to {attempted_value}: {temperature}"

    // TODO: Попробуйте установить вторую температуру и выведите результат
    // Формат: "After setting to {attempted_value}: {temperature}"
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming