Введение
В этом лабе мы будем исследовать тему обобщений, которая включает в себя обобщение типов и функциональностей для обработки более широкого круга случаев и уменьшения дублирования кода. Синтаксис обобщений в Rust включает в себя указание параметров типа с использованием угловых скобок, например, <T>. С использованием обобщений мы можем создавать обобщенные функции, которые могут принимать аргументы любого типа. Кроме того, мы можем определить обобщенные типы, которые могут работать с разными конкретными типами.
Примечание: Если в лабе не указано имя файла, вы можете использовать любое имя файла, которое хотите. Например, вы можете использовать
main.rs, скомпилировать и запустить его с помощьюrustc main.rs &&./main.
Обобщения
Обобщения - это тема обобщения типов и функциональностей для более широких случаев. Это чрезвычайно полезно для уменьшения дублирования кода по многим причинам, но может требовать довольно сложного синтаксиса. То есть быть обобщенным требует тщательного указания типов, для которых обобщенный тип фактически считается допустимым. Самый простой и распространенный случай использования обобщений - это параметры типа.
Параметр типа задается как обобщенный с использованием угловых скобок и заглавных букв, обычно обозначается как <T>. В Rust "обобщенным" также называется все, что принимает один или несколько обобщенных параметров типа <T>. Любой тип, заданный как обобщенный параметр типа, является обобщенным, а все остальное - конкретным (необобщенным).
Например, определение обобщенной функции под названием foo, которая принимает аргумент T любого типа:
fn foo<T>(arg: T) {... }
Поскольку T задан как обобщенный параметр типа с использованием <T>, он считается обобщенным при использовании здесь в качестве (arg: T). Это так даже если T был ранее определен как struct.
В этом примере показан некоторый синтаксис на практике:
// Конкретный тип `A`.
struct A;
// При определении типа `Single` первое использование `A` не предшествует `<A>`.
// Поэтому, `Single` - это конкретный тип, а `A` определен выше.
struct Single(A);
// ^ Вот первое использование типа `A` в `Single`.
// Здесь `<T>` предшествует первому использованию `T`, поэтому `SingleGen` - это обобщенный тип.
// Поскольку параметр типа `T` является обобщенным, он может быть чем угодно, включая
// конкретный тип `A`, определенный в начале.
struct SingleGen<T>(T);
fn main() {
// `Single` - это конкретный тип и явно принимает `A`.
let _s = Single(A);
// Создаем переменную `_char` типа `SingleGen<char>`
// и присваиваем ей значение `SingleGen('a')`.
// Здесь явно задан параметр типа для `SingleGen`.
let _char: SingleGen<char> = SingleGen('a');
// `SingleGen` также может иметь неявно заданный параметр типа:
let _t = SingleGen(A); // Использует `A`, определенный в начале.
let _i32 = SingleGen(6); // Использует `i32`.
let _char = SingleGen('a'); // Использует `char`.
}
Резюме
Поздравляем! Вы завершили лабу по Обобщениям. Вы можете практиковаться в других лабах в LabEx, чтобы улучшить свои навыки.