Обобщённые методы
Часть раздела Объектно-ориентированное программирование путешествия по Rust на Coddy. Урок 25 из 61.
Обобщённая структура может хранить значения любого типа, но без методов для работы с её данными она не очень полезна. Чтобы определить методы для обобщённой структуры, в блоке impl нужно использовать специальный синтаксис.
Главное — объявить параметр обобщённого типа непосредственно у impl:
struct Wrapper<T> {
value: T,
}
impl<T> Wrapper<T> {
fn get(&self) -> &T {
&self.value
}
}
Обрати внимание на impl<T> перед Wrapper<T>. Это сообщает Rust, что T — обобщённый параметр типа для всего блока реализации. Без этого объявления Rust искал бы конкретный тип с именем T и не смог бы его найти.
Метод get возвращает &T: ссылку на значение того типа, который хранится в обёртке. Это работает, независимо от того, является ли T целым числом, строкой или любым другим типом:
let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };
println!("{}", num_wrapper.get()); // 100
println!("{}", text_wrapper.get()); // Rust
Одно и то же определение метода подходит для обоих случаев, потому что обобщённый тип T адаптируется к каждому конкретному типу во время компиляции.
Задание
ЛегкоДавайте расширим ваш обобщённый контейнер методами! Вы создадите структуру Box (не путать со стандартной структурой Box в Rust), которая может хранить значения любого типа и предоставляет методы для работы с содержимым.
Вы распределите код по двум файлам:
mybox.rs: определите публичную обобщённую структуру с именемMyBox<T>и приватным полемcontentsтипаT. Реализуйте методы для этой структуры:- ассоциированную функцию
new, которая создаёт новый экземплярMyBoxс заданным значением; - метод
peek, который возвращает ссылку на содержимое (используя&self); - метод
replace, который принимает новое значение и заменяет им текущее содержимое (используя&mut self).
- ассоциированную функцию
main.rs: подключите свой модуль и продемонстрируйте работу обобщённых методов с разными типами. Вы создадите контейнеры, посмотрите на их содержимое и замените значения, чтобы показать, как работают методы.
Помните ключевой синтаксис реализации методов для обобщённой структуры: перед MyBox<T> нужно указать impl<T>, чтобы сообщить Rust, что T — это обобщённый параметр для всего блока реализации.
В главном файле продемонстрируйте работу MyBox следующим образом:
- Создайте контейнер с целым числом (первый ввод, преобразованный в
i32). - Посмотрите на его содержимое и выведите значение.
- Замените содержимое новым целым числом (второй ввод, преобразованный в
i32). - Посмотрите на содержимое ещё раз, чтобы показать обновлённое значение.
- Создайте второй контейнер со строкой (третий ввод).
- Посмотрите на содержимое контейнера со строкой.
Вывод должен соответствовать следующему формату:
Integer box contains: {value}
After replace: {value}
String box contains: {value}Например, если ввести 10, 25 и Rust:
Integer box contains: 10
After replace: 25
String box contains: RustВы получите три ввода: начальное целое число, целое число для замены и строковое значение.
Попробуйте сами
mod mybox;
use mybox::MyBox;
fn main() {
// Считать входные данные
let mut input1 = String::new();
std::io::stdin().read_line(&mut input1).expect("Failed to read line");
let initial_int: i32 = input1.trim().parse().expect("Invalid integer");
let mut input2 = String::new();
std::io::stdin().read_line(&mut input2).expect("Failed to read line");
let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");
let mut input3 = String::new();
std::io::stdin().read_line(&mut input3).expect("Failed to read line");
let string_value = input3.trim().to_string();
// TODO: Создать MyBox с исходным целым числом
// TODO: Посмотреть его содержимое и вывести: "Integer box contains: {value}"
// TODO: Заменить содержимое новым целым числом
// TODO: Снова посмотреть содержимое и вывести: "After replace: {value}"
// TODO: Создать второй MyBox со строковым значением
// TODO: Посмотреть содержимое блока со строкой и вывести: "String box contains: {value}"
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Методы и поведение
Введение в блоки реализацииПараметр SelfИзменяемые методыАссоциированные функцииНесколько блоков реализацииЦепочки вызовов методовИтоги: действия с Rectangle4Проект: Виртуальный питомец
Определение питомцаКормление питомца2Инкапсуляция и модули
Основы модулейКлючевое слово PublicПриватные поляГеттерыСеттерыИтоги — Безопасный сейф5Обобщения
Обобщённые структурыОбобщённые методыНесколько обобщённых типовОбобщённые функцииПовторение — Координатная точка8Трейты как ограничения
Синтаксис ограничений трейтовМножественные ограниченияКонструкция whereВозврат типов с трейтамиИтоги — Обобщённый принтер11Паттерны проектирования в Rust
Паттерн NewtypeКомпозицияТрейт DropFrom и IntoИтоги — Мок-объект Smart Pointer3Продвинутые перечисления
Перечисления с даннымиМетоды в перечисленияхСопоставление вариантов с даннымиСнова об Option EnumИтоги — перечисление Shape6Определение трейтов
Что такое трейт?Реализация трейтовРеализации по умолчаниюПереопределение реализаций по умолчаниюТрейты с параметрамиИтоги — Media PlayerПотренируйтесь самостоятельно: Онлайн-компилятор Rust