Обобщения
Обобщения (Generics) позволяют абстрагировать типы и функциональность для более общих случаев. Они
чрезвычайно полезны для снижения дублирования кода, однако их синтаксис может быть
сравнительно сложным. А именно, использование обобщений требует особого
внимания при определении того, какими реальными типами в действительности могут заменяться обобщённые.
Наиболее простым и распространённым применением обобщений является обобщение параметров
типа.
Обобщить параметр типа можно используя угловые скобки и верхний верблюжий регистр: <Aaa, Bbb, ...>
. "Обобщённые параметры типа" обычно представлены как <T>
. В Rust, "обобщённым" также принято называть все, что может принимать один или более обобщённых параметров типа <T>
. Любой тип, указанный в качестве параметра обобщённого типа, является обобщённым, а всё остальное является конкретным (не обобщённым).
Например, объявление обобщённой функции foo
принимающей аргумент T
любого типа:
fn foo<T>(arg: T) { ... }
Поскольку T
был объявлен как обобщённый тип, посредством <T>
, он считается обобщённым когда используется как (arg: T)
. Это работает даже если T
был определён как структура
.
Пример ниже демонстрирует синтаксис в действии:
// Конкретный тип `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`. }