Кортеж — это коллекция для хранения значений разных типов. Кортежи создаются с помощью круглых скобок (). Каждый кортеж сам по себе является независимым значением, его тип записывается как (T1, T2, ...), где T1 и T2 обозначают типы каждого члена внутри кортежа. Функции могут возвращать несколько результатов с помощью кортежей, поскольку один кортеж может содержать любое количество данных.
1 Использование кортежа как параметра и возвращаемого значения функции
// Кортежи можно использовать как входные параметры и возвращаемые значения функции
fn reverse(pair: (i32, bool)) -> (bool, i32) {
// Оператор let позволяет деструктурировать члены кортежа и привязать их к отдельным переменным
let (int_param, bool_param) = pair;
// Возврат нового кортежа с переставленным порядком элементов
(bool_param, int_param)
}
fn main(){
// (12, true) — полный двухэлементный кортеж, передаётся как один параметр
let res = reverse((12, true));
// Использовать индекс .0 для получения первого элемента возвращаемого кортежа
println!("{}", res.0);
}Code language: JavaScript (javascript)
Результат компиляции и выполнения
E:\rustdemo\demo>rustc demo.rs
E:\rustdemo\demo>demo
trueCode language: JavaScript (javascript)
2 Определение кортежной структуры (Tuple Struct)
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
fn main(){
let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
println!("{:?}", matrix);
}Code language: PHP (php)
Кортежная структура: сразу после имени структуры идут круглые скобки со списком типов, именованных полей нет, элементы различаются только по порядку;
Производный макрос #[derive(Debug)]: автоматически реализует трейт Debug для структуры, позволяет выводить отладочную информацию через {:?};
Matrix(f32,f32,f32,f32) по сути является специальным кортежем, оборачивающим четыре числа с плавающей точкой.
При запуске появится предупреждение, его можно игнорировать
E:\rustdemo\demo>rustc demo.rs
warning: fields `0`, `1`, `2`, and `3` are never read
--> demo.rs:2:15
|
2 | struct Matrix(f32, f32, f32, f32);
| ------ ^^^ ^^^ ^^^ ^^^
| |
| fields in this struct
|
= help: consider removing these fields
= note: `Matrix` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
= note: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default
warning: 1 warning emitted
E:\rustdemo\demo>demo
Matrix(1.1, 1.2, 2.1, 2.2)Code language: JavaScript (javascript)
3 Длинный кортеж с разными типами + получение значений по индексу
Сначала посмотрим пример
fn main(){
// Длинный кортеж с множеством разных типов данных
let long_tuple = (1u8, 2u16, 3u32, 4u64,
-1i8, -2i16, -3i32, -4i64,
0.1f32, 0.2f64,
'a', true);
// Внутренние значения можно извлекать по индексам кортежа
println!("Long tuple first value: {}", long_tuple.0);
println!("Long tuple second value: {}", long_tuple.1);
}Code language: JavaScript (javascript)
Допускается одновременное хранение данных разных типов (беззнаковые целые, знаковые целые, числа с плавающей точкой, символы и булевы значения могут сосуществовать) ;
Синтаксис индекса кортежа: переменная_кортежа.число, индексы начинаются с 0 ;
.0— получить первый элемент,.1— получить второй элемент ;- и так далее…
В качестве индекса можно использовать только фиксированную числовую константу, переменную использовать нельзя.
Ниже неотформатированная часть——
2. Определение кортежной структуры (Tuple Struct)
// Следующая структура для домашних упражнений
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
Code language: PHP (php)
Сопутствующие теоретические сведения
- Кортежная структура: после имени структуры идут круглые скобки со списком типов. Именованных полей нет, элементы различаются только по порядку ;
- Производный макрос
#[derive(Debug)]: автоматически реализует трейтDebugдля структуры, поддерживает отладочный вывод через{:?}; Matrix(f32,f32,f32,f32)по сути является специальным кортежем, оборачивающим четыре числа с плавающей точкой.
Полный пример ниже
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
fn main() {
// 1. Создать экземпляр
let mat = Matrix(1.0, 2.0, 3.0, 4.0);
// 2. Вывести на экран (нужен #[derive(Debug)] для использования {:?})
println!("Экземпляр матрицы: {:?}", mat);
// 3. Доступ к внутренним элементам через .индекс
let a = mat.0;
let b = mat.1;
let c = mat.2;
let d = mat.3;
println!("a={}, b={}, c={}, d={}", a, b, c, d);
// 4. Получение значений через деструктуризацию
// Matrix(m0, m1, m2, m3) — паттерн деструктуризации. m0/m1/m2/m3 — пользовательские временные переменные, принимающие значения четырёх кортежных членов структуры.
let Matrix(m0, m1, m2, m3) = mat;
println!("Деструктуризация:{} {} | {} {}", m0, m1, m2, m3);
// 5. Изменяемая матрица, изменение элементов через mut
let mut mat_mut = Matrix(0.0, 0.0, 0.0, 0.0);
mat_mut.0 = 10.0;
mat_mut.3 = 99.0; // Значения можно изменять
println!("Изменяемая матрица: {:?}", mat_mut);
}Code language: PHP (php)
Результат выполнения
E:\rustdemo\demo>demo
Экземпляр матрицы: Matrix(1.0, 2.0, 3.0, 4.0)
a=1, b=2, c=3, d=4
Деструктуризация:1 2 | 3 4
Изменяемая матрица: Matrix(10.0, 0.0, 0.0, 99.0)
3 Длинный кортеж с разными типами + получение значений по индексу
fn main() {
// Длинный кортеж с множеством разных типов данных
let long_tuple = (1u8, 2u16, 3u32, 4u64,
-1i8, -2i16, -3i32, -4i64,
0.1f32, 0.2f64,
'a', true);
// Values can be extracted from the tuple using tuple indexing.
// Внутренние значения можно извлекать по индексам кортежа
println!("Long tuple first value: {}", long_tuple.0);
println!("Long tuple second value: {}", long_tuple.1);
}
Code language: JavaScript (javascript)
Результат выполнения
E:\rustdemo\demo>demo
Long tuple first value: 1
Long tuple second value: 2
Итог
- Основная особенность кортежей: допускается одновременное хранение данных разных типов (беззнаковые целые, знаковые целые, числа с плавающей точкой, символы и булевы значения могут сосуществовать) ;
- Синтаксис индекса кортежа:
переменная_кортежа.число, индексы начинаются с 0 ;.0— получить первый элемент,.1— получить второй элемент ;
- В качестве индекса можно использовать только фиксированную числовую константу, переменную использовать нельзя.
4 Вложенные кортежи
fn main() {
// Члены кортежа сами могут быть кортежами, поддерживается вложенность
let tuple_of_tuples = ((1u8, 2u16, 2u32), (4u64, -1i8), -2i16);
// Кортежи поддерживают отладочный вывод
println!("tuple of tuples: {:?}", tuple_of_tuples);
// Использовать два последовательных . для вывода значения
println!("tuple of tuples: {:?}", tuple_of_tuples.0.1); // Выведет 2
}
Code language: JavaScript (javascript)
Вывод
E:\rustdemo\demo>demo
tuple of tuples: ((1, 2, 2), (4, -1), -2)
tuple of tuples: 2
Итог
- Поддерживается многоуровневая вложенность кортежей, элементы внешнего кортежа могут быть подкортежами ;
- Кортежи с ≤12 элементами автоматически реализуют трейт
Debug, спецификатор формата{:?}позволяет сразу вывести всё содержимое.
5 Ограничение вывода для сверхдлинных кортежей (ошибка компиляции)
fn main() {
// Сверхдлинные кортежи с более 12 элементами нельзя выводить напрямую через Debug
let too_long_tuple = (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
println!("Too long tuple: {:?}", too_long_tuple);
// Подсказка: раскомментируйте две строки выше, чтобы увидеть ошибку компилятора
}
Code language: JavaScript (javascript)
Ошибка компиляции
E:\rustdemo\demo>rustc demo.rs
error[E0277]: `({integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer})` doesn't implement `Debug`
--> demo.rs:5:38
|
5 | println!("Too long tuple: {:?}", too_long_tuple);
| ---- ^^^^^^^^^^^^^^ `({integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer})` cannot be formatted using `{:?}` because it doesn't implement `Debug`
| |
| required by this formatting parameter
|
= help: the trait `Debug` is not implemented for `({integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer}, {integer})`
= help: the following other types implement trait `Debug`:
()
(A, Z, Y, X, W, V, U, T)
(B, A, Z, Y, X, W, V, U, T)
(C, B, A, Z, Y, X, W, V, U, T)
(D, C, B, A, Z, Y, X, W, V, U, T)
(E, D, C, B, A, Z, Y, X, W, V, U, T)
(T,)
(U, T)
and 5 others
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0277`.Code language: PHP (php)
Итог
Стандартная библиотека Rust автоматически генерирует реализацию трейта Debug только для кортежей с 0–12 элементами ;
Кортежи с количеством элементов больше 12 не имеют встроенной реализации Debug, прямой вывод через {:?} вызовет ошибку компиляции.
Удалите цифру 13 выше и протестируйте, чтобы убедиться, что ошибка исчезнет
6 Вызов функции с кортежным параметром, просмотр переставленного результата
// Кортежи можно использовать как входные параметры и возвращаемые значения функции
fn reverse(pair: (i32, bool)) -> (bool, i32) {
// Оператор let позволяет деструктурировать члены кортежа и привязать их к отдельным переменным
let (int_param, bool_param) = pair;
// Возврат нового кортежа с переставленным порядком элементов
(bool_param, int_param)
}
fn main() {
let pair = (1, true);
println!("Pair is {:?}", pair);
println!("The reversed pair is {:?}", reverse(pair)); // Вызвать reverse для перестановки порядка
}Code language: JavaScript (javascript)
Результат выполнения
E:\rustdemo\demo>demo
Pair is (1, true)
The reversed pair is (true, 1)Code language: JavaScript (javascript)
Итог
- Обычный двухэлементный кортеж можно передавать напрямую как аргумент функции, принимающей кортеж ;
- Функция возвращает полностью новый кортеж, исходный кортеж
pairне изменяется.
7 Особое правило запятой для одноэлементных кортежей (частая ошибка)
fn main() {
// При создании одноэлементного кортежа запятая обязательна, чтобы отличить его от обычного литерала в скобках
println!("One element tuple: {:?}", (5u32,));
println!("Just an integer: {:?}", (5u32));
}Code language: JavaScript (javascript)
Итог
(5u32,): есть запятая в конце, это корректный одноэлементный кортеж, тип(u32,);(5u32): без запятой, это просто обычное число5u32в скобках, не кортеж ;- Запятая — единственный разделитель между одноэлементным кортежем и скобочным выражением.
8 Полная деструктуризация многоэлементных кортежей (см. выше)
// Кортеж можно полностью деструктурировать, одновременно привязав несколько переменных
let tuple = (1, "hello", 4.5, true);
let (a, b, c, d) = tuple;
println!("{:?}, {:?}, {:?}, {:?}", a, b, c, d);
Code language: JavaScript (javascript)
Итог
- Кортеж любой длины можно полностью деструктурировать, количество переменных слева должно полностью совпадать с количеством элементов кортежа ;
- После деструктуризации каждая переменная соответствует значению на той же позиции кортежа и может использоваться отдельно.
9 Создание экземпляра кортежной структуры и отладочный вывод Debug
#[derive(Debug)]
struct Matrix(f32, f32, f32, f32);
fn main() {
let matrix = Matrix(1.1, 1.2, 2.1, 2.2);
println!("{:?}", matrix);
}Code language: PHP (php)
Итог
- Синтаксис создания экземпляра кортежной структуры:
ИмяСтруктуры(значение1, значение2, ...); - При добавлении
#[derive(Debug)]структура поддерживает отладочный вывод через{:?}.