Примитивный тип tuple
Кортеж — конечная разнородная последовательность: (T, U, ..).
Рассмотрим каждое свойство по порядку:
Свойства кортежей
-
Конечность: Кортеж имеет длину. Например, кортеж длины 3:
#![allow(unused)] fn main() { ("hello", 5, 'c'); }Длина также называется "арностью" (arity). Каждый кортеж разной длины — это отдельный, уникальный тип.
-
Разнородность: Каждый элемент кортежа может иметь разный тип. Указанный выше кортеж имеет тип:
#![allow(unused)] fn main() { (&'static str, i32, char) } -
Последовательность: Элементы кортежа доступны по позиции с помощью "индексации кортежа":
#![allow(unused)] fn main() { let tuple = ("hello", 5, 'c'); assert_eq!(tuple.0, "hello"); assert_eq!(tuple.1, 5); assert_eq!(tuple.2, 'c'); }
Последовательная природа кортежа влияет на реализации различных трейтов. Например, в PartialOrd и Ord элементы сравниваются последовательно до первого несовпадающего набора.
Реализации трейтов
В документации используется сокращение (T₁, T₂, …, Tₙ) для представления кортежей различной длины. Когда это используется, любая граница трейта, выраженная на T, применяется к каждому элементу кортежа независимо. Это обозначение для удобства документации, а не валидный синтаксис Rust.
Трейты с ограничением по длине (до 12 элементов)
Из-за временных ограничений в системе типов Rust следующие трейты реализованы только для кортежей длиной до 12 элементов:
| Трейт | Описание |
|---|---|
PartialEq, Eq | Проверка на равенство |
PartialOrd, Ord | Сравнение |
Debug | Отладочный вывод |
Default | Значение по умолчанию |
Hash | Хеширование |
From<[T; N]> | Преобразование из массива |
Трейты для кортежей любой длины
Следующие трейты реализованы для кортежей любой длины. Их реализации автоматически генерируются компилятором:
| Трейт | Описание |
|---|---|
Clone, Copy | Клонирование и копирование |
Send, Sync | Многопоточность |
Unpin | Перемещение |
UnwindSafe, RefUnwindSafe | Безопасность при раскрутке стека |
Таблица реализаций трейтов
Основные трейты
| Трейт | Элементы | Версия | Примечание |
|---|---|---|---|
Debug | T: Debug | 1.0.0 | До 12 элементов |
Default | T: Default | 1.0.0 | До 12 элементов |
Hash | T: Hash | 1.0.0 | До 12 элементов |
Ord | T: Ord | 1.0.0 | До 12 элементов |
PartialEq | T: PartialEq | 1.0.0 | До 12 элементов |
PartialOrd | T: PartialOrd | 1.0.0 | До 12 элементов |
Eq | T: Eq | 1.0.0 | До 12 элементов |
Трейты коллекций
| Трейт | Тип | Версия | Описание |
|---|---|---|---|
Extend<(K, V)> | BTreeMap<K, V, A> | 1.0.0 | Расширение BTreeMap парами |
Extend<(K, V)> | HashMap<K, V, S> | 1.0.0 | Расширение HashMap парами |
Extend<(&K, &V)> | BTreeMap<K, V, A> | 1.2.0 | Расширение ссылками на пары |
Extend<(&K, &V)> | HashMap<K, V, S> | 1.4.0 | Расширение ссылками на пары |
Extend<(T₁, T₂, …, Tₙ)> | (ExtendT₁, ExtendT₂, …) | 1.56.0 | Расширение кортежей коллекций |
FromIterator<(K, V)> | BTreeMap<K, V> | 1.0.0 | Создание из итератора пар |
FromIterator<(K, V)> | HashMap<K, V, S> | 1.0.0 | Создание из итератора пар |
FromIterator<(T₁, T₂, …, Tₙ)> | (ExtendT₁, ExtendT₂, …) | 1.79.0 | Создание кортежей коллекций |
Преобразования From/Into
| Преобразование | Назначение | Версия | Описание |
|---|---|---|---|
[T; N] → (T₁, T₂, …, Tₙ) | Кортеж | 1.71.0 | До 12 элементов |
(T₁, T₂, …, Tₙ) → [T; N] | Массив | 1.71.0 | До 12 элементов |
(I, u16) → SocketAddr | Адрес сокета | 1.17.0 | Из IP-адреса и порта |
Трейты для работы с диапазонами
| Трейт | Тип | Версия | Описание |
|---|---|---|---|
RangeBounds<T> | (Bound<T>, Bound<T>) | 1.28.0 | Границы диапазона |
RangeBounds<T> | (Bound<&T>, Bound<&T>) | 1.28.0 | Границы диапазона по ссылке |
IntoBounds<T> | (Bound<T>, Bound<T>) | nightly | Преобразование в границы |
SliceIndex<[T]> | (Bound<usize>, Bound<usize>) | 1.53.0 | Индексация срезов |
SliceIndex<str> | (Bound<usize>, Bound<usize>) | 1.73.0 | Индексация строк |
Сетевые трейты
| Трейт | Тип | Версия | Описание |
|---|---|---|---|
ToSocketAddrs | (&str, u16) | 1.0.0 | Преобразование в адреса сокетов |
ToSocketAddrs | (IpAddr, u16) | 1.0.0 | Преобразование в адреса сокетов |
ToSocketAddrs | (Ipv4Addr, u16) | 1.0.0 | Преобразование в адреса сокетов |
ToSocketAddrs | (Ipv6Addr, u16) | 1.0.0 | Преобразование в адреса сокетов |
ToSocketAddrs | (String, u16) | 1.46.0 | Преобразование в адреса сокетов |
Примеры
Базовое использование
#![allow(unused)] fn main() { let tuple = ("hello", 5, 'c'); assert_eq!(tuple.0, "hello"); }
Использование как возвращаемого типа
#![allow(unused)] fn main() { fn calculate_point() -> (i32, i32) { (4, 5) } let point = calculate_point(); assert_eq!(point.0, 4); assert_eq!(point.1, 5); // С использованием паттернов let (x, y) = calculate_point(); assert_eq!(x, 4); assert_eq!(y, 5); }
Создание из массива
#![allow(unused)] fn main() { let array: [u32; 3] = [1, 2, 3]; let tuple: (u32, u32, u32) = array.into(); }
Использование Extend с кортежами коллекций
#![allow(unused)] fn main() { let mut tuple = (vec![0], vec![1]); tuple.extend([(2, 3), (4, 5), (6, 7)]); assert_eq!(tuple.0, [0, 2, 4, 6]); assert_eq!(tuple.1, [1, 3, 5, 7]); }
Использование FromIterator
#![allow(unused)] fn main() { let string = "1,2,123,4"; let (numbers, lengths): (Vec<_>, Vec<_>) = string .split(',') .map(|s| s.parse().map(|n: u32| (n, s.len()))) .collect::<Result<_, _>>()?; assert_eq!(numbers, [1, 2, 123, 4]); assert_eq!(lengths, [1, 1, 3, 1]); }
Использование как диапазона
#![allow(unused)] fn main() { let range = (Bound::Included(0), Bound::Excluded(10)); let slice = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; let subslice = &slice[range]; assert_eq!(subslice, &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); }
Особые реализации
Служебные трейты (для любых длин)
CloneFromCell— для кортежей до 12 элементов (еслиT: CloneFromCell)ConstParamTy_— для кортежей до 12 элементов (еслиT: ConstParamTy_)StructuralPartialEq— для кортежей до 12 элементов
Автоматические реализации (для любых длин)
Freeze,RefUnwindSafe,Send,Sync,Unpin,UnwindSafe— если все элементы реализуют соответствующий трейт
Примечания
- Индексация: Индексы кортежа начинаются с 0:
tuple.0,tuple.1, и т.д. - Сравнение: Кортежи сравниваются лексикографически, последовательно сравнивая элементы.
- Длина: В текущей версии Rust (1.0.0+) многие трейты ограничены кортежами длиной до 12 элементов, но это может измениться в будущем.
- Паттерны: Кортежи отлично работают с деструктуризацией в паттернах.