Menu
Coddy logo textTech

Обобщённые структуры

Часть раздела Объектно-ориентированное программирование путешествия по Rust на Coddy. Урок 24 из 61.

До сих пор каждая созданная тобой структура имела поля с определёнными конкретными типами. У Pet есть имя типа String, у Rectangle — размеры типа f64. Но что, если ты хочешь создать структуру, которая может содержать данные любого типа any?

Именно здесь на помощь приходят обобщения. Обобщения позволяют писать гибкий, повторно используемый код, работающий с несколькими типами. Вместо жёсткого задания конкретного типа вы используете заполнитель, обычно T, который заменяется конкретным типом при использовании struct.

Вот простая оболочка-структура, которая может содержать любой тип:

struct Wrapper<T> {
    value: T,
}

<T> после имени struct объявляет обобщённый параметр типа. Внутри struct T выступает в качестве заменителя типа, который ты фактически будешь использовать. Когда ты создаёшь экземпляр, Rust выводит конкретный тип:

let int_wrapper = Wrapper { value: 42 };        // T — это i32
let float_wrapper = Wrapper { value: 3.14 };    // T — это f64
let text_wrapper = Wrapper { value: "hello" };  // T — это &str

Каждый из них — это отдельный конкретный тип: Wrapper<i32>, Wrapper<f64> и Wrapper<&str>, но все они используют одно и то же определение структуры. Это избавляет от необходимости писать отдельные структуры IntWrapper, FloatWrapper и StringWrapper, которые по сути делают одно и то же.

Буква T — это всего лишь соглашение (сокращение от «Тип»). Вы могли бы использовать любой допустимый идентификатор, но T является стандартом в Rust и большинстве других языков с обобщёнными типами.

challenge icon

Задание

Легко

Давайте создадим generic контейнер, который может hold значение любого типа! Вы создадите Container struct, демонстрирующий, как generic делают ваш код гибким и повторно используемым.

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

  • container.rs: Define public generic struct called Container<T> с single public field item типа T. Этот контейнер должен уметь hold любой type: integer, float, string или что-либо ещё.
  • main.rs: Подключите свой модуль container и продемонстрируйте его гибкость, Create containers, которые hold разные типы data. Вы Create three containers и отобразите, что hold каждый из них.

В своём основном файле Create следующие containers:

  1. Контейнер, holding integer value (первый input, разобранный как i32)
  2. Контейнер, holding float value (второй input, разобранный как f64)
  3. Контейнер, holding string (третий input, сохранённый как String)

Ваш output should отображать contents каждого контейнера в этом формате:

Integer container: {value}
Float container: {value}
String container: {value}

Например, с inputs 42, 3.14 и hello:

Integer container: 42
Float container: 3.14
String container: hello

Обратите внимание, как одно и то же определение Container<T> работает для всех three разных типов: в этом и заключается сила generic!

Вы получите three inputs: integer value, float value и string value.

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

mod container;

use container::Container;

fn main() {
    // Прочитать три входных значения
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let int_value: i32 = input1.trim().parse().expect("Failed to parse integer");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let float_value: f64 = input2.trim().parse().expect("Failed to parse float");

    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: Create three containers using Container<T>
    // 1. An integer container holding int_value
    // 2. A float container holding float_value
    // 3. A string container holding string_value

    // TODO: Вывести содержимое каждого контейнера в требуемом формате
    // Integer container: {value}
    // Float container: {value}
    // String container: {value}
}
quiz iconПроверьте себя

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

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

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