Данные и управление

Шаблоны и управление потоком

Как выбрать if, match или for и извлечь данные с помощью шаблонов.

Используйте if, когда нужно проверить одно условие, match — когда результат зависит от формы или категории значения, а for — когда действие повторяется для каждого элемента. Шаблоны внутри match и for одновременно проверяют данные и дают имена нужным частям.

Запустите пример

Сохраните код в файле data-control.tpz:

TOPAZ
record StudyTask {
    title: string,
    minutes: int,
    done: bool = false,
}

function pace(task: StudyTask) -> string {
    if task.done {
        return "done"
    }
    match task.minutes {
        case 1..15 => "quick"
        case 16..30 => "focused"
        case _ => "deep"
    }
}

let tasks: Array<StudyTask> = [
    StudyTask { title: "Run first program", minutes: 10, done: true },
    StudyTask { title: "Build application", minutes: 25 },
]
let mut remaining = 0
for task in tasks {
    if !task.done {
        remaining = remaining + task.minutes
    }
    print("{task.title}: {pace(task)}")
}
print("remaining: {remaining} minutes")

Сначала проверьте программу, затем выполните её:

BASH
topaz check data-control.tpz
topaz run data-control.tpz

Строки появятся в порядке элементов массива:

Вывод
Run first program: done
Build application: focused
remaining: 25 minutes

Проследите за тремя решениями

Цикл связывает очередной элемент массива с именем task. Вложенный if отвечает на один вопрос: задача ещё не выполнена? Здесь не требуется ни разбирать значение на части, ни выбирать из нескольких категорий.

Когда важны оба исхода, пишите if condition { ... } else { ... }. Если ветви возвращают совместимые значения, весь if тоже является значением.

В функции pace первый if отдельно обрабатывает выполненную задачу. Затем match вычисляет task.minutes один раз и проверяет ветки case сверху вниз. 1..15 и 16..30 — шаблоны диапазонов. _ принимает все остальные целые числа, поэтому результат определён для любого входа.

ФормаКогда выбиратьРезультат
ifВыбор зависит от одного логического условияЗначение при совместимых результатах ветвей либо только действие
matchУ значения есть несколько значимых форм или категорийЗначение выбранной ветви и доступные в ней связанные имена
forНужно посетить каждый элемент в установленном порядкеДействия в позиции инструкции либо Array результатов в позиции выражения

Шаблон проверяет и связывает

Литеральный шаблон и шаблон диапазона проверяют значение. Имя вроде task связывается с совпавшим значением. Шаблоны конструкторов Some(value) и Err(message) извлекают содержимое Option и Result. Шаблон записи выбирает поля по именам.

В шаблоне массива остаток обозначается .., а не .... Форма case [head, ..tail] => связывает первый элемент с head, а остальные — с tail типа Array. Если оставшееся значение не нужно, используйте _.

Форма if let pattern = value { ... } удобна, когда важен один успешный вариант и, возможно, запасная ветвь. while let повторяет ту же проверку до первого несовпадения. Созданные ими имена неизменяемы и видны только в успешном блоке.

Частая ошибка

Не пишите [head, ...tail] в шаблоне. ... раскрывает массив в литерале или аргументы при вызове. Каноническая запись остатка списка — [head, ..tail].

Создание и разбор перечисления тоже записываются по-разному. Значение создают с именем перечисления, например Status.Paused("review"), а в шаблоне оставляют только вариант: case Paused(reason) =>.

Точные правила, влияющие на выбор

  • Ветви if или match, используемых как значение, должны давать совместимые результаты.
  • Для закрытого перечисления проверяется полнота вариантов. Ветка с дополнительным условием не засчитывается как полное покрытие варианта.
  • Если проверяющий не может доказать полноту match, добавьте явную ветвь _.
  • Части шаблона проверяются слева направо. Имена из неудачной альтернативы не переходят в следующую.
  • Несовпадение допускающего отказ шаблона во включении коллекции вызывает ошибку, а не пропускает элемент. Для фильтрации добавьте явное условие if.
  • Порядок обхода определён для Array, целочисленных диапазонов, Set и map.keys. Строки напрямую не обходятся.
  • while и for в позиции инструкции не дают значения. for в позиции выражения собирает результаты тела в исходном порядке.

Пользовательские шаблоны и итераторы, генераторы, перехват ошибок выполнения и метки на while или for в текущий язык не входят.

Начните с примера курса Данные и управление. Формы данных подробно разобраны в разделе Записи и номинальные данные, а порядок обхода и фильтрация — в разделе Коллекции и включения.