Цепочки вызовов методов
Часть раздела Object Oriented Programming путешествия по Rust на Coddy — урок 6 из 61.
До сих пор наши изменяемые методы модифицировали структуру и ничего не возвращали. Но что, если мы хотим вызвать несколько методов подряд для одного и того же экземпляра? Возвращая ссылку на self, мы делаем возможной цепочку вызовов методов — паттерн, при котором несколько вызовов методов объединяются в одно выражение.
Ключ в том, чтобы ваши методы &mut self возвращали &mut Self:
struct Config {
debug: bool,
timeout: u32,
}
impl Config {
fn new() -> Config {
Config { debug: false, timeout: 30 }
}
fn set_debug(&mut self, value: bool) -> &mut Self {
self.debug = value;
self
}
fn set_timeout(&mut self, seconds: u32) -> &mut Self {
self.timeout = seconds;
self
}
}
Каждый метод изменяет struct, затем возвращает self — изменяемую ссылку на тот же экземпляр. Это позволяет следующему вызову метода немедленно продолжить работу с ним:
fn main() {
let mut config = Config::new();
config.set_debug(true).set_timeout(60);
println!("Debug: {}, Timeout: {}", config.debug, config.timeout);
// Вывод: Debug: true, Timeout: 60
}
Вместо того чтобы писать три отдельных инструкции, мы настраиваем всё в одну непрерывную строку. Этот паттерн «строитель» (builder-style) особенно полезен при настройке объектов с множеством необязательных параметров, что делает ваш код более лаконичным и читаемым.
Задание
ЛегкоСоздайте структуру TextStyle с тремя полями: bold (bool), italic (bool) и size (u32).
Добавьте блок реализации для TextStyle со следующим содержимым:
new— ассоциированная функция, которая возвращаетTextStyleсbold, установленным вfalse,italicвfalse, иsizeв12set_bold— принимает&mut selfи значениеbool, устанавливает поле bold и возвращает&mut Selfдля цепочки вызововset_italic— принимает&mut selfи значениеbool, устанавливает поле italic и возвращает&mut Selfдля цепочки вызововset_size— принимает&mut selfи значениеu32, устанавливает поле size и возвращает&mut Selfдля цепочки вызовов
Вы получите три входных значения:
- Первая строка: настройка bold (
trueилиfalse) - Вторая строка: настройка italic (
trueилиfalse) - Третья строка: размер шрифта (u32)
Создайте изменяемую переменную TextStyle, используя new, затем используйте цепочку методов для применения всех трех настроек в одном выражении. Выведите конечное состояние в формате, показанном ниже.
Ожидаемый формат вывода:
Bold: {bold}, Italic: {italic}, Size: {size}Шпаргалка
Методы, которые принимают &mut self, могут возвращать &mut Self для реализации цепочки вызовов методов (method chaining):
impl Config {
fn set_debug(&mut self, value: bool) -> &mut Self {
self.debug = value;
self
}
fn set_timeout(&mut self, seconds: u32) -> &mut Self {
self.timeout = seconds;
self
}
}
Это позволяет выполнять несколько вызовов методов в одном выражении:
let mut config = Config::new();
config.set_debug(true).set_timeout(60);
Каждый метод изменяет структуру и возвращает изменяемую ссылку на тот же экземпляр, позволяя следующему методу немедленно продолжить работу с ним.
Попробуйте сами
use std::io;
// TODO: Определите структуру TextStyle здесь
// TODO: Добавьте блок реализации для TextStyle с:
// - ассоциированной функцией new()
// - методом set_bold()
// - методом set_italic()
// - методом set_size()
fn main() {
let mut input = String::new();
// Чтение настройки жирного шрифта
io::stdin().read_line(&mut input).expect("Failed to read line");
let bold: bool = input.trim().parse().expect("Invalid bool");
input.clear();
// Чтение настройки курсива
io::stdin().read_line(&mut input).expect("Failed to read line");
let italic: bool = input.trim().parse().expect("Invalid bool");
input.clear();
// Чтение настройки размера
io::stdin().read_line(&mut input).expect("Failed to read line");
let size: u32 = input.trim().parse().expect("Invalid u32");
// TODO: Создайте изменяемый TextStyle, используя new(), затем используйте цепочку методов,
// чтобы применить все три настройки в одном выражении
// TODO: Выведите результат в формате: Bold: {bold}, Italic: {italic}, Size: {size}
}В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Методы и поведение
Введение в блоки реализацииПараметр SelfИзменяемые методыАссоциированные функцииНесколько блоков реализацииЦепочки вызовов методовИтоги: действия с Rectangle4Проект: Виртуальный питомец
Определение питомцаКормление питомца2Инкапсуляция и модули
Основы модулейКлючевое слово PublicПриватные поляГеттерыСеттерыИтоги — Безопасный сейф5Обобщения
Обобщённые структурыОбобщённые методыНесколько обобщённых типовОбобщённые функцииПовторение — Координатная точка8Трейты как ограничения
Синтаксис ограничений трейтовМножественные ограниченияКонструкция whereВозврат типов с трейтамиИтоги — Обобщённый принтер11Паттерны проектирования в Rust
Паттерн NewtypeКомпозицияТрейт DropFrom и IntoИтоги — Мок-объект Smart Pointer3Продвинутые перечисления
Перечисления с даннымиМетоды в перечисленияхСопоставление вариантов с даннымиСнова об Option EnumИтоги — перечисление Shape6Определение трейтов
Что такое трейт?Реализация трейтовРеализации по умолчаниюПереопределение реализаций по умолчаниюТрейты с параметрамиИтоги — Media Player