Menu
Coddy logo textTech

Обобщённые функции

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

Обобщённые типы не ограничиваются структурами. Вы также можете писать отдельные функции, которые работают с любым типом. Это полезно, когда вам нужна вспомогательная функция, не относящаяся к определённой структуре, но при этом остающаяся гибкой.

Синтаксис похож на то, что вы уже видели в структурах. Объявите generic-параметр в угловых скобках после имени function, затем используйте его в parameters и возвращаемом типе:

fn identity<T>(value: T) -> T {
    value
}

Эта функция identity принимает значение любого типа и возвращает его без изменений. <T> объявляет generic, value: T принимает его в качестве параметра, а -> T указывает возвращаемый тип. Когда вы вызываете function, Rust выводит конкретный тип:

let num = identity(42);        // T — это i32
let text = identity("hello");  // T — это &str

Вы также можете использовать несколько generic параметров в функциях, как и в структурах:

fn make_pair<T, U>(first: T, second: U) -> (T, U) {
    (first, second)
}

let pair = make_pair(10, "ten");  // возвращает (i32, &str)

Обобщённые функции let вам один раз записать повторно используемую логику и применять её к многим типам, уменьшая дублирование кода и сохраняя безопасность типов.

challenge icon

Задание

Легко

Давайте создадим utility-модуль с generic function, которые могут работать с любым типом! Вы создадите самостоятельные function, демонстрирующие, как generics делают ваш код гибким и повторно используемым, не привязывая его к определённой структуре.

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

  • utils.rs: создайте набор общедоступных generic utility function:
    • wrap_in_pair<T>: принимает single значение и returns tuple, containing это значение дважды: (value, value). Для этого требуется, чтобы тип поддерживал Clone, поэтому используйте <T: Clone>
    • swap<T, U>: принимает два значения потенциально разных типов и returns их в reversed order в виде tuple (U, T)
  • main.rs: импортируйте utility-модуль и продемонстрируйте работу этих generic function с разными типами. Покажите, как одни и те же определения function без проблем обрабатывают integer, числа с плавающей точкой и strings.

В основном файле продемонстрируйте свои utility function следующим образом:

  1. Используйте wrap_in_pair с integer (first input, разобранным как i32) и выведите оба элемента
  2. Используйте wrap_in_pair со string (second input) и выведите оба элемента
  3. Используйте swap с integer (third input, разобранным как i32) и string (fourth input), затем выведите swapped result

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

Pair of ints: ({value}, {value})
Pair of strings: ({value}, {value})
Swapped: ({string}, {int})

Например, для inputs 5, hello, 42 и world:

Pair of ints: (5, 5)
Pair of strings: (hello, hello)
Swapped: (world, 42)

Обратите внимание, как wrap_in_pair работает одинаково для integer и strings, а swap обрабатывает два полностью разных типа: в этом и заключается гибкость generic function!

Вы получите four inputs: integer, string, ещё один integer и ещё один string.

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

mod utils;

use std::io;

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

    let mut input2 = String::new();
    io::stdin().read_line(&mut input2).expect("Failed to read line");
    let str1 = input2.trim().to_string();

    let mut input3 = String::new();
    io::stdin().read_line(&mut input3).expect("Failed to read line");
    let num2: i32 = input3.trim().parse().expect("Invalid integer");

    let mut input4 = String::new();
    io::stdin().read_line(&mut input4).expect("Failed to read line");
    let str2 = input4.trim().to_string();

    // TODO: Используйте wrap_in_pair с num1 и выведите результат
    // Format: Pair of ints: ({value}, {value})

    // TODO: Используйте wrap_in_pair с str1 и выведите результат
    // Format: Pair of strings: ({value}, {value})

    // TODO: Используйте swap с num2 и str2, затем выведите результат обмена
    // Формат: Обменяно: ({string}, {int})
}
quiz iconПроверьте себя

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

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

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