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

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

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

Эта страница описывает Топаз v5.17. Прежде чем считать её актуальной, сверьте поле version в /version.json со значением 5.17.

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

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

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

TOPAZ
record УчебнаяЗадача {
    название: string,
    минуты: int,
    выполнена: bool = false,
}

function темп(задача: УчебнаяЗадача) -> string {
    if задача.выполнена {
        return "done"
    }
    match задача.минуты {
        case 1..15 => "quick"
        case 16..30 => "focused"
        case _ => "deep"
    }
}

let задачи: Array<УчебнаяЗадача> = [
    УчебнаяЗадача { название: "Run first program", минуты: 10, выполнена: true },
    УчебнаяЗадача { название: "Build application", минуты: 25 },
]
let mut осталось = 0
for задача in задачи {
    if !задача.выполнена {
        осталось = осталось + задача.минуты
    }
    print("{задача.название}: {темп(задача)}")
}
print("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 тоже является значением.

В функции темп первый if отдельно обрабатывает выполненную задачу. Затем match вычисляет задача.минуты один раз и проверяет ветки 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].

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

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

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

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

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