Rust: с нуля до своего органайзера Урок 26 из 40
Кортеж: два результата одной функции
Урок 26. Вернуть название и длительность задачи вместе, не смешав их значения.
Текст переведён с помощью ИИ.
Предварительно: уроки 9, 14, 19 и 22. Если возврат значения функции забылся, повторите урок 14.
Образ и опорная карта
На карточке задачи написаны название и число минут. Карточка одна, но у неё два места с разным содержимым. Кортеж — одно значение из нескольких элементов в заданном порядке; элементы могут иметь разные типы. Его длина и тип каждого места известны при компиляции. Образ ограничен: на бумажной карточке места можно произвольно переименовать, а у кортежа места обозначаются позициями. Если важны имена полей, в следующем уроке создадим структуру.
Два значения → скобки и запятая → один кортеж → возврат → разбор на имена. Сначала воспроизведите цепочку без кода. Запись (String, u32) означает тип кортежа: на первом месте владеющее название String, на втором — целое число u32. Запись (title, minutes) создаёт такое значение. Запятая разделяет места; круглые скобки собирают их в одно. Порядок имеет значение: (u32, String) — другой тип.
Возвращаем пару
Сохраните прежний src/main.rs проекта organizer, замените файл целиком и запустите cargo run в папке с Cargo.toml. Других файлов и зависимостей не нужно. Сначала предскажите результат без сообщений Cargo.
У функции first_task после стрелки -> указан один возвращаемый тип (String, u32). Последняя строка без ; возвращает кортеж. В let (title, minutes) = first_task(); запись слева разбирает кортеж: первый элемент получает имя title, второй — minutes. Это называют распаковкой; она связывает места с именами, а не создаёт два независимых результата функции.
fn first_task() -> (String, u32) {
let title = String::from("Чтение");
let minutes = 20;
(title, minutes)
}
fn main() {
let (title, minutes) = first_task();
println!("{title}: {minutes} мин");
}
Чтение: 20 мин
String перешёл из функции в кортеж и затем в title; это правило владения из урока 19. Число u32 допускает копирование. Кортеж удобен для короткого промежуточного результата, когда значение каждого места ясно рядом с кодом.
Позиции и граница образа
Если нужен один элемент, после имени кортежа ставят точку и номер места: .0 — первое, .1 — второе. Нумерация начинается с нуля, как индексы массива. В отдельном примере ниже _u32 после 25 явно задаёт тип числа; урок 10 уже разбирал числовые типы. true — логическое значение из урока 11. Кортеж хранит число и флаг о том, хватило ли времени.
fn main() {
let report = (25_u32, true);
println!("Минут: {}", report.0);
println!("Успели: {}", report.1);
}
Минут: 25
Успели: true
Здесь оба элемента копируются при чтении. Если же взять String через .0 из кортежа, владение строкой может перейти к новой переменной; это не способ бесплатно скопировать текст. Кортеж из двух элементов не имеет места .2. Этот отдельный пример намеренно не компилируется с E0609:
fn main() {
let report = (20_u32, true);
println!("{}", report.2);
}
Не путайте (20, true) с массивом [20, true]: массив требует одного типа элементов, а кортеж допускает разные. Пустые скобки () из урока 14 обозначают кортеж без элементов и единичное значение; одна запятая в (20,) создаёт кортеж с одним элементом, в отличие от просто (20) — числа в скобках.
Восстановите карту
- Почему функция с типом
(String, u32)всё же возвращает одно значение? - Какое место берёт
.1? - Чем
(20,)отличается от(20)?
Проверьте себя: кортеж — одно составное значение; .1 берёт второе место; запятая делает однокомпонентный кортеж. Закройте страницу и проговорите цепочку «два значения → один кортеж → возврат → разбор».
Задание
Обязательное. Напишите plan() -> (String, u32), которая возвращает Прогулка и 30. В main разберите результат на title и minutes, затем выведите Прогулка — 30 мин. Число и название должны приходить из функции, а не из готовой строки в println!.
Проверка границы. Поменяйте порядок элементов в возвращаемом значении, но оставьте объявленный тип прежним. Прочитайте ошибку компилятора и верните порядок назад.
Подсказка
Последним выражением функции сделайте (String::from("Прогулка"), 30). Слева от = в main напишите (title, minutes).
Эталон после попытки
fn plan() -> (String, u32) {
(String::from("Прогулка"), 30)
}
fn main() {
let (title, minutes) = plan();
println!("{title} — {minutes} мин");
}
Прогулка — 30 мин
Кортеж сохранил два разных типа вместе, а распаковка дала каждому результату понятное имя. Официальный разбор кортежей.
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.