Основы
if в Zero выглядит примерно как if в любом другом языке C-семейства, с одним заметным ограничением: условие должно быть bool.
Условие value == 42 — это bool, потому что == между двумя i32 возвращает bool. В каждой из двух веток лежит блок инструкций. Любую ветку можно опустить — else необязательна, — но если обе присутствуют, обе должны быть блоками { ... }.
Требование bool
Некоторые языки позволяют написать if value { ... } и считают 0, "" или null «ложными». Zero — нет. Условие должно быть настоящим bool.
let count = 0
if count { // compile error: expected bool, got i32
// ...
}
if count == 0 { // ОК
check world.out.write("nothing to do\n")
}
Причина та же, что и в остальном языке: явное лучше неявного. Агент, читающий вторую форму, точно знает, что именно проверяется. Первая форма оставляет правила truthiness неявными, и они меняются между языками — Zero от этого отказывается.
Else и else-if
Ветка else выполняется, когда условие ложно:
Условия можно сцепить через else if:
if value < 0 {
check world.out.write("negative\n")
} else if value == 0 {
check world.out.write("zero\n")
} else {
check world.out.write("positive\n")
}
else if — это просто else { if ... } с убранными скобками: семантика та же, отступов меньше. Финальный else необязателен.
Откуда берётся условие
Условие может быть чем угодно, что вычисляется в bool:
- Привязка типа
bool:if ok { ... }. - Сравнение:
if value == 42 { ... },if x < y { ... }. - Логическая комбинация:
if a && b { ... },if pair.left == 1_u8 && pair.right == 2_u8 { ... }. - Вызов функции, возвращающей
bool:if isReady(world) { ... }.
Фрагмент из реальных примеров языка:
let pair: BytePair = Pair { left: 1_u8, right: 2_u8 }
if pair.left == 1_u8 && pair.right == 2_u8 {
check world.out.write("type alias ok\n")
} else {
check world.out.write("type alias broke\n")
}
&& коротко замыкает, как и ожидаешь: если левая часть false, правая не вычисляется. То же и для ||.
Когда вместо этого нужен match
Цепочки if/else if хороши для двух- или трёхсторонних решений, особенно когда условия не разделяют общей структуры. Но когда вы ветвитесь по вариантам sum-типа — choice или enum — правильный инструмент это match.
Сравните:
// match — исчерпывающий, проверяется компилятором
match result {
.ok => value { check world.out.write("ok\n") }
.err => message { check world.out.write("err\n") }
}
vs.
// if/else по sum-типу — многословно и легче ошибиться
if result.isOk() {
let value = result.unwrap()
check world.out.write("ok\n")
} else {
check world.out.write("err\n")
}
Форма match делает разбор вариантов явным, и компилятор пожалуется, если позже добавили вариант, а обработать его забыли. Форма if молча пропустит всё, что не ok, в ветку else — включая совершенно новые варианты, о которых вы никогда не думали.
Правило: if для булевых, match для вариантов.
Стиль
Несколько маленьких соглашений, которые делают код легче для чтения и людьми, и агентами:
- Всегда оборачивайте тело в скобки. Даже однострочное тело — в
{ ... }. Однострочной формы без скобок здесь нет. Это специально — так отступы остаются надёжными и убирается частый источник багов в C-семействе. - Сначала самая частая ветка. Читатели (и агенты) скользят сверху вниз.
- Предпочитайте позитивные условия, когда они так же ясны.
if isReadyчитать легче, чемif !notReady, при прочих равных.
Дальше: While Loops
Условия решают что делать; циклы — сколько раз. Следующая статья посвящена while loops — конструкции цикла раннего этапа, с которой поставляется язык.
Часто задаваемые вопросы
Как работают конструкции if в Zero?
Используйте if condition { ... } с необязательной веткой else { ... }. Условие должно быть bool — Zero не приводит целые, строки и другие значения к булеву. Пример: if value == 42 { check world.out.write("yes\n") } else { check world.out.write("no\n") }.
Есть ли в Zero тернарный оператор?
Zero намеренно держит поверхность маленькой и использует блоки if / else, а не отдельный тернарник condition ? a : b. Официальные примеры предпочитают явные ветки даже в коротких случаях. Если в языке появится if-как-выражение, ожидайте, что Zero пойдёт в эту сторону, а не введёт второй синтаксис.
Можно ли в Zero делать цепочки if/else if?
Да. Соединяйте условия через else if: if a { ... } else if b { ... } else { ... }. Для более сложного ветвления по choice или enum берите вместо этого match — он более исчерпывающий, и компилятор проверит, что вы обработали каждый вариант.
Почему Zero не приводит значения к bool?
Философия дизайна Zero — «всё явное». Неявная truthiness — трактовать 0, "" или null как false — это частый источник багов и сложно для агента, чтобы рассуждать о ней точно. Требование настоящего bool делает решение о ветвлении видимым в исходниках и легче проверяемым механически.
Когда использовать match вместо if/else?
Используйте match, когда ветвитесь по вариантам choice или enum. Компилятор проверит, что вы покрыли каждый случай, чего цепочки if/else if сделать не могут. if/else оставьте для простых булевых предикатов — проверок на равенство, сравнений и коротких двусторонних ветвлений.