Shanraq.org Shanraq.org
Option: когда записи может не быть
IT

Rust: с нуля до своего органайзера Урок 31 из 40

Option: когда записи может не быть

Урок 31. Искать название по позиции без аварии, если позиции нет.

Текст переведён с помощью ИИ.

Предварительно: уроки 15, 23–24 и 29–30. Если ветки match забылись, повторите урок 30.

Образ и опорная карта

В картотеке можно попросить карточку с номером, которого в лотке нет. Библиотекарь либо отдаёт карточку, либо честно говорит, что такой карточки нет. Option<T> — стандартное перечисление Rust для значения, которое может отсутствовать. Его варианты: Some(T) содержит значение типа T, None означает отсутствие. Образ ограничен: None не сообщает, почему карточки нет; для причины ошибки в следующем уроке понадобится другой тип.

Запрос → Option<T>Some(значение) или None → обе ветки match. Угловые скобки из Vec<String> теперь указывают тип возможного содержимого. В Option<&String> возможное содержимое — ссылка на String, а не новая строка. Some и None доступны без дополнительной команды импорта. Нельзя считать, что Option<T> уже является T: сначала обработайте вариант.

Безопасно читаем список

Сохраните прежний src/main.rs проекта organizer, замените файл целиком и выполните cargo run рядом с Cargo.toml. Другие файлы и зависимости не меняются. Предскажите две строки вывода.

Метод .get(index) у Vec запрашивает элемент по позиции. В отличие от titles[index], неверная позиция не останавливает программу: результат имеет тип Option<&String>. Some(title) в match даёт имя ссылке на найденный текст; None обрабатывает отсутствие. Список создаётся знакомыми Vec::new() и push из урока 24. Индекс 0 существует, индекс 2 у списка длины 1 — нет.

fn main() {
    let mut titles: Vec<String> = Vec::new();
    titles.push(String::from("Чтение"));
    for index in [0, 2] {
        match titles.get(index) {
            Some(title) => println!("Найдено: {title}"),
            None => println!("Нет записи на позиции {index}"),
        }
    }
}
Найдено: Чтение
Нет записи на позиции 2

Список имеет один String. get не копирует название и не передаёт его владение: найденное значение заимствовано у titles.

Отсутствие не равно пустому тексту

Some(String::from("")) означает: значение есть, но текст пустой. None означает: значения вообще нет. Это разные состояния. None без подсказки о типе иногда не даёт компилятору понять, что могло бы быть внутри; запись let missing: Option<String> = None; явно задаёт тип. Для titles.get(index) тип уже известен из списка.

Если попробовать присвоить результат .get() обычной ссылке без разбора, компилятор остановит отдельный пример с E0308:

fn main() {
    let mut titles: Vec<String> = Vec::new();
    titles.push(String::from("Чтение"));
    let title: &String = titles.get(0);
    println!("{title}");
}

Правильный путь — match с Some и None или другой явно объяснённый способ обработки отсутствия. В органайзере позиции списка пока не являются постоянными ID задач: get лишь предотвращает выход за границу, но не решает задачу устойчивого номера из будущего урока 38.

Проверка понимания

  1. Чем Option<&String> отличается от &String?
  2. Означает ли None, что найден пустой текст?
  3. Почему .get(2) не вызывает panic для списка длины 1?

Проверьте: ссылка может отсутствовать; нет, пустой текст тоже был бы значением; get возвращает None. Закройте страницу и восстановите опорную карту.

Задание

Обязательное. Создайте список с названиями Чтение и Прогулка. Через .get() запросите позиции 1 и 2 и обработайте обе через match. Выведите Найдено: Прогулка и Позиция 2 отсутствует. Не проверяйте длину вручную и не подставляйте готовое название в сообщение.

Граница. Создайте пустой список и объясните, что вернёт .get(0).

Подсказка

Для каждого index в [1, 2] выполните match titles.get(index). В Some(title) печатайте найденный title, в None — номер index.

Эталон после попытки

fn main() {
    let mut titles: Vec<String> = Vec::new();
    titles.push(String::from("Чтение"));
    titles.push(String::from("Прогулка"));
    for index in [1, 2] {
        match titles.get(index) {
            Some(title) => println!("Найдено: {title}"),
            None => println!("Позиция {index} отсутствует"),
        }
    }
}
Найдено: Прогулка
Позиция 2 отсутствует

Здесь список остаётся владельцем названий, а отсутствие обрабатывается явно. Официальный разбор Option.

Предыдущий урок · Оглавление · Следующий урок

Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом

Комментарии (0)

Пока нет комментариев. Будьте первым.