Menu
Coddy logo textTech

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

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

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

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

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

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

Обратите внимание, что Wallet является публичным, но 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;          // Ошибка! невозможно получить доступ к приватному полю
}

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

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

challenge icon

Задание

Легко

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

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

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

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

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

Sensor created for: {location}

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

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

Sensor created for: Kitchen

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

Шпаргалка

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

Чтобы сделать поле приватным, просто опустите ключевое слово pub:

pub struct Wallet {
    balance: f64,  // Нет pub = приватное поле
}

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

В этом примере Wallet является публичной (может использоваться вне модуля), но balance является приватным (не может быть доступно напрямую извне).

Внешний код может создавать экземпляры, используя публичные конструкторы, но не может читать или изменять приватные поля:

mod wallet;
use wallet::Wallet;

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

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

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

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Проверьте себя

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

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