Menu
Coddy logo textTech

Приватные поля

Часть раздела Объектно-ориентированное программирование путешествия по Rust на Coddy. Урок 10 из 61.

На предыдущем уроке вы сделали всё public: struct, его поля и его методы. Но настоящая инкапсуляция означает контроль над тем, как можно получить доступ к вашим данным. В Rust вы можете сделать struct public, сохранив его поля private.

Рассмотрим Wallet, у которого никогда не должно быть отрицательного баланса. Если поле является public, любой может установить ему любое значение:

// wallet.rs
pub struct Wallet {
    balance: f64,  // Нет pub = приватный!
}

impl Wallet {
    pub fn new(initial: f64) -> Wallet {
        Wallet { balance: initial }
    }
}

Обратите внимание, что Wallet является public, но у balance нет ключевого слова pub. Это означает, что код за пределами модуля может создать Wallet с помощью конструктора, но не может напрямую читать или изменять поле balance:

// main.rs
mod wallet;
use wallet::Wallet;

fn main() {
    let w = Wallet::new(100.0);
    // println!("{}", w.balance);  // Ошибка! поле приватное
    // w.balance = -50.0;          // Ошибка! нельзя получить доступ к приватному полю
}

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

В следующих уроках ты узнаешь, как предоставить контролируемый доступ к этим private данным с помощью методов getter и setter.

challenge icon

Задание

Легко

Давайте создадим систему датчика температуры, демонстрирующую инкапсуляцию за счёт защиты конфиденциальных данных внутри модуля.

Вы создадите два файла, чтобы организовать свой код:

  • sensor.rs: Определите структуру TemperatureSensor с двумя полями: location (String) и reading (f64). Структура должна быть общедоступной, чтобы её можно было использовать из других файлов, но оба поля должны оставаться private: внешний код не должен иметь возможности напрямую получать доступ к данным датчика или изменять их. Добавьте общедоступный конструктор new, который принимает название location и initial показание температуры.
  • main.rs: Подключите модуль датчика и создайте TemperatureSensor using конструктор. Поскольку поля являются private, вы не сможете напрямую вывести их, поэтому вместо этого выведите сообщение подтверждения, показывающее, что датчик был успешно создан.

В этом задании основное внимание уделяется концепции private полей: структура доступна, но её внутренние данные защищены. Внешний код может взаимодействовать с датчиком только через предоставленные вами методы (в данном случае только через конструктор).

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

Sensor created for: {location}

Чтобы получить location для вывода, вам нужно, чтобы функция new вывела это сообщение перед возвратом датчика, поскольку само поле является private.

Например, если вы создадите датчик с location "Kitchen" и показанием 22.5, вывод будет таким:

Sensor created for: Kitchen

Вы получите два входных значения: название location и initial показание температуры.

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

mod sensor;

use sensor::TemperatureSensor;

fn main() {
    // Чтение ввода
    let mut location = String::new();
    std::io::stdin().read_line(&mut location).expect("Failed to read line");
    let location = location.trim().to_string();
    
    let mut reading_str = String::new();
    std::io::stdin().read_line(&mut reading_str).expect("Failed to read line");
    let reading: f64 = reading_str.trim().parse().expect("Failed to parse reading");
    
    // TODO: Создать TemperatureSensor с помощью конструктора
    // Функция new обработает вывод сообщения подтверждения
    
}
quiz iconПроверьте себя

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

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Rust