Menu
CoddyTech

Обобщённые методы

Часть раздела Объектно-ориентированное программирование путешествия по 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 адаптируется к каждому конкретному типу во время компиляции.

challenge icon

Задание

Легко

Давайте расширим ваш обобщённый контейнер методами! Вы создадите структуру 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 следующим образом:

  1. Создайте контейнер с целым числом (первый ввод, преобразованный в i32).
  2. Посмотрите на его содержимое и выведите значение.
  3. Замените содержимое новым целым числом (второй ввод, преобразованный в i32).
  4. Посмотрите на содержимое ещё раз, чтобы показать обновлённое значение.
  5. Создайте второй контейнер со строкой (третий ввод).
  6. Посмотрите на содержимое контейнера со строкой.

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

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

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

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

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