Menu

Zero If/Else: условное ветвление с объяснением

Как работают if и else в Zero: булевы условия, тела веток, отсутствие truthy-коэрсии и как условия соседствуют с match для более богатого ветвления.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Основы

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 оставьте для простых булевых предикатов — проверок на равенство, сравнений и коротких двусторонних ветвлений.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ