Shanraq.org Shanraq.org
Структура Task: данные с понятными именами
IT

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

Структура Task: данные с понятными именами

Урок 27. Собрать название, длительность и состояние задачи в один собственный тип.

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

Предварительно: уроки 9, 11, 19, 22 и 26. Если круглые скобки кортежа ещё непривычны, вернитесь к уроку 26.

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

На карточке задачи есть подписанные графы: «название», «минуты», «сделано». В кортеже пришлось бы помнить, что означает .0 или .1. Структура (struct) — собственный тип с именованными полями. Поле хранит одну часть значения; экземпляр — конкретная заполненная карточка. Образ ограничен: бумажная форма не проверяет тип написанного, а компилятор требует указанные поля и их типы. При этом структура сама по себе не проверяет смысл, например что минут больше нуля.

Тип Task → поля → экземпляр → чтение через точку → изменение через mut. Проговорите карту до примера. Ключевое слово struct объявляет тип. После Task стоят фигурные скобки с полями вида имя: тип, разделёнными запятыми. Это описание формы, а не созданная задача. Имя Task пишем с большой буквы по принятому в Rust стилю типов.

Заполняем карточку

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

Task { title: ..., minutes: ..., done: ... } создаёт экземпляр. В отличие от кортежа, каждому значению здесь соответствует имя поля. task.title читает поле после точки. Значение String не нужно перемещать ради печати: println! использует его для форматирования, и после печати задача остаётся доступна. done имеет уже знакомый тип bool. Запятая после последнего поля допускается и помогает добавлять поля без изменения предыдущей строки.

struct Task {
    title: String,
    minutes: u32,
    done: bool,
}

fn main() {
    let task = Task {
        title: String::from("Чтение"),
        minutes: 20,
        done: false,
    };
    println!("Задача: {}", task.title);
    println!("Минут: {}", task.minutes);
    println!("Сделано: {}", task.done);
}
Задача: Чтение
Минут: 20
Сделано: false

Порядок перечисления полей при создании может отличаться от порядка объявления: имена удерживают смысл.

Меняем запись и проверяем смысл

let mut task разрешает менять поля этого экземпляра. task.done = true записывает новое логическое значение; точка здесь обращается к полю, а не к методу. Для определения структуры mut не требуется. Проверка task.minutes > 0 — наше правило для органайзера, а не встроенная гарантия struct: нулевое число имело бы правильный тип u32, но неверный смысл для этой задачи.

struct Task {
    title: String,
    minutes: u32,
    done: bool,
}

fn main() {
    let mut task = Task {
        title: String::from("Прогулка"),
        minutes: 30,
        done: false,
    };
    if task.minutes > 0 {
        task.done = true;
    }
    println!("{}: {}", task.title, task.done);
}
Прогулка: true

Здесь условие лишь показывает место проверки. Позже введём способ, который не позволит создать неподходящую задачу через отдельную функцию и сообщит причину ошибки. Пока ввод пользователя не принимаем, поэтому не выдаём этот пример за полную проверку данных.

Все объявленные поля надо заполнить. В следующем отдельном примере забыто done, и компилятор сообщает E0063:

struct Task {
    title: String,
    minutes: u32,
    done: bool,
}

fn main() {
    let task = Task {
        title: String::from("Чтение"),
        minutes: 20,
    };
    println!("{}", task.title);
}

Компилятор проверяет наличие и тип полей, но не знает, сколько минут разумно выделить для прогулки. Так заканчивается полезность образа «готовой формы».

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

  1. Чем Task отличается от одного task?
  2. Почему task.minutes яснее, чем report.1?
  3. Гарантирует ли minutes: u32, что минут больше нуля?

Проверьте: первое — описание типа, второе — экземпляр; имя поля сообщает его роль; нет, ноль входит в u32. Воспроизведите карту по памяти.

Задание

Обязательное. Объявите Task с тремя полями из урока. Создайте изменяемую задачу Уборка, 15 минут, false; выведите Уборка: 15 мин, сделано false, затем измените done на true и выведите После: true. Используйте значения полей, не вписывайте результат готовой строкой.

Граница. Попробуйте создать задачу без minutes, прочитайте сообщение компилятора и верните поле.

Подсказка

Нужны let mut task = Task { ... };, затем task.done = true;. В println! передайте поля либо подставьте их по именам.

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

struct Task {
    title: String,
    minutes: u32,
    done: bool,
}

fn main() {
    let mut task = Task {
        title: String::from("Уборка"),
        minutes: 15,
        done: false,
    };
    println!(
        "{}: {} мин, сделано {}",
        task.title, task.minutes, task.done
    );
    task.done = true;
    println!("После: {}", task.done);
}
Уборка: 15 мин, сделано false
После: true

Теперь данные задачи лежат вместе и читаются по именам. Поведение рядом с ними добавим в следующем уроке. Официальный разбор структур.

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

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

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

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