Приватные поля
Часть раздела Объектно-ориентированное программирование путешествия по 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.
Задание
ЛегкоДавайте создадим систему датчика температуры, демонстрирующую инкапсуляцию за счёт защиты конфиденциальных данных внутри модуля.
Вы создадите два файла, чтобы организовать свой код:
sensor.rs: Определите структуруTemperatureSensorс двумя полями:location(String) иreading(f64). Структура должна быть общедоступной, чтобы её можно было использовать из других файлов, но оба поля должны оставаться private: внешний код не должен иметь возможности напрямую получать доступ к данным датчика или изменять их. Добавьте общедоступный конструкторnew, который принимает название location и initial показание температуры.main.rs: Подключите модуль датчика и создайтеTemperatureSensorusing конструктор. Поскольку поля являются 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 обработает вывод сообщения подтверждения
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Методы и поведение
Введение в блоки реализацииПараметр SelfИзменяемые методыАссоциированные функцииНесколько блоков реализацииЦепочки вызовов методовИтоги: действия с Rectangle4Проект: Виртуальный питомец
Определение питомцаКормление питомца2Инкапсуляция и модули
Основы модулейКлючевое слово PublicПриватные поляГеттерыСеттерыИтоги — Безопасный сейф5Обобщения
Обобщённые структурыОбобщённые методыНесколько обобщённых типовОбобщённые функцииПовторение — Координатная точка8Трейты как ограничения
Синтаксис ограничений трейтовМножественные ограниченияКонструкция whereВозврат типов с трейтамиИтоги — Обобщённый принтер11Паттерны проектирования в Rust
Паттерн NewtypeКомпозицияТрейт DropFrom и IntoИтоги — Мок-объект Smart Pointer3Продвинутые перечисления
Перечисления с даннымиМетоды в перечисленияхСопоставление вариантов с даннымиСнова об Option EnumИтоги — перечисление Shape6Определение трейтов
Что такое трейт?Реализация трейтовРеализации по умолчаниюПереопределение реализаций по умолчаниюТрейты с параметрамиИтоги — Media PlayerПотренируйтесь самостоятельно: Онлайн-компилятор Rust