Кортежи Tuples

Кортеж — это коллекция для хранения значений разных типов. Кортежи создаются с помощью круглых скобок (). Каждый кортеж сам по себе является независимым значением, его тип записывается как (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)

Сопутствующие теоретические сведения

  1. Кортежная структура: после имени структуры идут круглые скобки со списком типов. Именованных полей нет, элементы различаются только по порядку ;
  2. Производный макрос #[derive(Debug)]: автоматически реализует трейт Debug для структуры, поддерживает отладочный вывод через {:?} ;
  3. 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

Итог

  1. Основная особенность кортежей: допускается одновременное хранение данных разных типов (беззнаковые целые, знаковые целые, числа с плавающей точкой, символы и булевы значения могут сосуществовать) ;
  2. Синтаксис индекса кортежа: переменная_кортежа.число, индексы начинаются с 0 ;
    • .0 — получить первый элемент,
    • .1 — получить второй элемент ;
  3. В качестве индекса можно использовать только фиксированную числовую константу, переменную использовать нельзя.

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

Итог

  1. Поддерживается многоуровневая вложенность кортежей, элементы внешнего кортежа могут быть подкортежами ;
  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)

Итог

  1. Обычный двухэлементный кортеж можно передавать напрямую как аргумент функции, принимающей кортеж ;
  2. Функция возвращает полностью новый кортеж, исходный кортеж pair не изменяется.

7 Особое правило запятой для одноэлементных кортежей (частая ошибка)


   fn main() {
 
    // При создании одноэлементного кортежа запятая обязательна, чтобы отличить его от обычного литерала в скобках
    println!("One element tuple: {:?}", (5u32,)); 
    println!("Just an integer: {:?}", (5u32));

}Code language: JavaScript (javascript)

Итог

  1. (5u32,): есть запятая в конце, это корректный одноэлементный кортеж, тип (u32,) ;
  2. (5u32): без запятой, это просто обычное число 5u32 в скобках, не кортеж ;
  3. Запятая — единственный разделитель между одноэлементным кортежем и скобочным выражением.

8 Полная деструктуризация многоэлементных кортежей (см. выше)


    // Кортеж можно полностью деструктурировать, одновременно привязав несколько переменных
    let tuple = (1, "hello", 4.5, true);

    let (a, b, c, d) = tuple;
    println!("{:?}, {:?}, {:?}, {:?}", a, b, c, d);
Code language: JavaScript (javascript)

Итог

  1. Кортеж любой длины можно полностью деструктурировать, количество переменных слева должно полностью совпадать с количеством элементов кортежа ;
  2. После деструктуризации каждая переменная соответствует значению на той же позиции кортежа и может использоваться отдельно.

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. Синтаксис создания экземпляра кортежной структуры: ИмяСтруктуры(значение1, значение2, ...) ;
  2. При добавлении #[derive(Debug)] структура поддерживает отладочный вывод через {:?}.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *