Обобщения
Обобщения позволяют обобщить типы и функциональность для более общих случаев. Они чрезвычайно полезны благодаря уменьшению дублирования кода, однако могут привести к сравнительному усложнению синтаксиса. А именно, использование обобщений требует особого внимания при определении допустимых реальных типов которыми могут заменяться обобщённые. Наиболее простым и распространённым применением обобщений является обобщение параметров типа.
Обобщить параметр типа можно используя угловые скобки и верхний верблюжий регистр: . "Обобщённые параметры типа" обычно представлены как . В Rust, "обобщённым" также принято называть все, что может принимать один или более обобщённых параметров типа . Любой тип, указанный в качестве параметра обобщённого типа, является обобщённым, а всё остальное является конкретным (не обобщённым).
Например, объявление обобщённой функции foo принимающей аргумент T любого типа:
fn foo(arg: T) { ... }
Поскольку T был объявлен как обобщённый тип, посредством , он считается обобщённым когда используется как (arg: T). Это работает даже если T был определён как структура.
Пример ниже демонстрирует синтаксис в действии:
// Конкретный тип `A`.
struct A;
// В определении типа `Single` первому использованию `A` не предшествует ``.
// Поэтому `Single` имеет конкретный тип, и `A` определена выше.
struct Single(A);
// ^ Здесь `A` в первый раз используется в `Single`.
// В данном примере, `` предшествует первому использованию `T`,
// поэтому `SingleGen` является обобщённым типом.
// Поскольку тип параметра `T` является обобщённым, он может быть чем угодно, включая
// конкретный тип `A`, определённый выше.
struct SingleGen(T);
fn main() {
// `Single` имеет конкретный тип и явно принимает параметр `A`.
let _s = Single(A);
// Создаём переменную `_char` типа `SingleGen`
// и присваиваем ей значение `SingleGen('a')`.
// В примере ниже, тип параметра `SingleGen` явно определён.
let _char: SingleGen = SingleGen('a');
// Здесь, `SingleGen` также может иметь неявно определённый параметр типа:
let _t = SingleGen(A); // Используется структура `A`, объявленная выше.
let _i32 = SingleGen(6); // Используется `i32`.
let _char = SingleGen('a'); // Используется `char`.
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Смотрите также:
Структуры
Функции
Тот же набор правил применяется и к функциям: тип T становится обобщённым, когда предшествует .
При использовании обобщённых функций, иногда требуется явно указывать тип данных параметров. Это может быть необходимо в случае, если вызываемая функция возвращает обобщённый тип или у компилятора недостаточно информации для вывода необходимого типа данных.
Вызов функции с явно указанными типами данных параметров выглядит так: fun::().
struct A; // Конкретный тип `A`.
struct S(A); // Конкретный тип `S`.
struct SGen(T); // Обобщённый тип `SGen`.
// Все следующие функции становятся владельцем переменной, переданной в них.
// После передачи, она сразу выходит из области видимости и освобождается.
// Объявляем функцию `reg_fn`, которая принимает аргумент `_s` типа `S`.
// Здесь отсутствует ``, поэтому это не обобщённая функция.
fn reg_fn(_s: S) {}
// Объявляем функцию `gen_spec_t`, которая принимает аргумент `_s` типа `SGen`.
// В ней явно задан параметр типа `A`, но поскольку `A` не был указан
// как параметр обобщённого типа для `gen_spec_t`, то он не является обобщённым.
fn gen_spec_t(_s: SGen) {}
// Объявляем функцию `gen_spec_i32`, которая принимает аргумент `_s` типа `SGen`.
// В ней явно задан тип `i32`, который является определённым типом.
// Поскольку `i32` не является обобщённым типом, эта функция
// также не является обобщённой.
fn gen_spec_i32(_s: SGen) {}
// Объявляем функцию `generic`, которая принимает аргумент `_s` типа `SGen`.
// Поскольку `SGen` предшествует ``, эта функция
// является обобщённой над `T`.
fn generic(_s: SGen) {}
fn main() {
// Используем не обобщённые функции.
reg_fn(S(A)); // Конкретный тип.
gen_spec_t(SGen(A)); // Неявно определён тип параметра `A`.
gen_spec_i32(SGen(6)); // Неявно определён тип параметра `i32`.
// Явно определён тип параметра `char` в `generic()`.
generic::(SGen('a'));
// Неявно определён параметр типа `char` в `generic()`.
generic(SGen('c'));
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Смотрите также:
Функции и структуры
Реализация
Подобно функциям, реализации требуют выполнения некоторых условий, чтобы оставаться обобщёнными.
#![allow(unused)]
fn main() {
struct S; // Конкретный тип `S`
struct GenericVal(T); // Обобщенный тип `GenericVal`
// Реализация GenericVal, где мы явно указываем типы данных параметров:
impl GenericVal {} // Указываем тип `f32`
impl GenericVal {} // Указываем тип `S`, который мы определили выше
// `` должен указываться перед типом, чтобы оставаться обобщённым
impl GenericVal {}
}
struct Val {
val: f64,
}
struct GenVal {
gen_val: T,
}
// Реализация Val
impl Val {
fn value(&self) ->&f64 {
&self.val
}
}
// Реализация GenVal для обобщённого типа `T`
impl GenVal {
fn value(&self) ->&T {
&self.gen_val
}