Пишем файл
Откройте редактор и сохраните следующие пять строк как hello.0 где-нибудь под рукой — или просто нажмите Run на блоке ниже:
И всё — полноценная программа на Zero. Чтобы запустить её локально:
zero run hello.0
Должны увидеть:
hello from zero
Если получили command not found, вернитесь к Установке Zero и сначала убедитесь, что zero --version работает.
Разбираем каждый токен
Даже эта крошечная программа уже показывает почти всё, чем Zero отличается от других. Прочитаем её слева направо.
pub
pub помечает объявление как публичное — видимое за пределами текущего модуля. Рантайм должен найти main извне области видимости файла, поэтому main обязан быть pub. Приватной функции-помощнику внутри того же файла это не понадобилось бы.
fun
fun вводит объявление функции. Zero использует fun, а не fn (Rust), func (Go) или function (JavaScript). Одно ключевое слово, всегда одинаково.
main
Привычное имя точки входа. Когда исполняемая цель Zero запускается, рантайм ищет pub fun main(world: World) и вызывает её. Другие функции вы можете называть как угодно, но main зарезервировано по соглашению за точкой входа программы.
(world: World)
Единственный параметр называется world и имеет тип World. Рантайм конструирует значение World перед вызовом main и передаёт его внутрь. В этом значении лежат capability программы: доступ к stdout, stdin, файловой системе, сети и так далее — в зависимости от того, что рантайм решит выдать.
Имя параметра вы выбираете сами — (w: World) или (io: World) тоже скомпилируется. Соглашение в примерах — world, его и придерживаемся.
-> Void
Тип возвращаемого значения. Void означает, что функция не возвращает ничего полезного — она существует ради побочных эффектов, а не ради своего значения. Многие функции, которые вы будете писать, возвращают реальные типы вроде i32 или ваш собственный shape.
raises
Голый raises (без конкретного типа ошибки) у main говорит «эта функция может упасть». Для main это значит, что программа может выйти с ненулевым статусом, если какой-то check в теле пробросит ошибку выше. Более узкие формы — например, raises { InvalidInput } — увидим в Raises и Check.
check world.out.write("hello from zero\n")
Это строка, которая реально что-то делает. Три подчасти:
world.out— стандартный поток вывода, доступный как поле capabilityWorld..write("hello from zero\n")— метод, который пишет строку в этот поток. Он возвращает результат, который может означать неудачу (запись может провалиться, поток может быть закрыт).check— пробрасывает эту неудачу выше, если она случится. Безcheckкомпилятор бы возмутился, что результатwriteмолча выкидывается.
\n в конце — литеральный перевод строки. Без него вывод не уйдёт на новую строку, и приглашение шелла окажется на той же строке, что и ваше сообщение.
Что только что произошло
Когда вы запустили zero run hello.0:
- Компилятор распарсил ваш файл и проверил типы.
- Создал маленький нативный исполняемый файл под вашу платформу.
- Рантайм сконструировал capability
Worldдля текущего процесса. - Вызвал
main(world). - Ваш код записал «hello from zero\n» в поток
outэтого World — он соединён со stdout вашего терминала. mainвернулаVoid, рантайм прибрал за собой, и программа вышла со статусом 0.
Никакого сборщика мусора, никакой скрытой инициализации рантайма, никакого неявного bootstrap модулей. Вся программа — это функция, которую вы написали, плюс код стандартной библиотеки, который она вызвала.
Попробуйте небольшое изменение
Сделайте так, чтобы программа сначала привязала сообщение к имени, а потом записала:
Запустите снова — вывод тот же, но теперь вы увидели let-привязки и убедились, что строки — это полноценные значения, которые можно передавать.
Вариант, который падает
Что будет, если забыть check?
pub fun main(world: World) -> Void raises {
world.out.write("oops\n")
}
zero check hello.0 откажется это компилировать. Результат write — это значение, которое может содержать ошибку, и просто игнорировать его — это compile error. Либо вы check-аете его (пробрасывая ошибку), либо обрабатываете явно. Это та же идея, что у Rust-овских must_use-результатов, только применяется к каждому fallible-вызову.
Дальше: Zero CLI
Здесь вы использовали zero run. У CLI есть небольшой набор команд, которые стоит знать — check, run, build, test, fix, explain — и у каждой есть структурированный режим --json для агентов.
Часто задаваемые вопросы
Как выглядит программа hello world на Zero?
Каноничный hello world на Zero — пять строк: pub fun main(world: World) -> Void raises { check world.out.write("hello from zero\n") }. Сохраните как hello.0 и запустите zero run hello.0.
Что означает pub fun main в Zero?
pub fun main в Zero?pub делает объявление публичным — видимым за пределами модуля. fun объявляет функцию. main — это привычная точка входа, которую Zero ищет в исполняемой цели. Вместе pub fun main объявляет публичную точку входа, которую рантайм вызывает при старте программы.
Почему main принимает параметр World?
World?В Zero нет глобального I/O. Всё, что общается с внешним миром — stdout, stdin, файлы, сеть — идёт через capability, переданные явно. Рантайм отдаёт main значение World, и это значение (или его части) — единственный способ для функций делать I/O. Так побочные эффекты становятся видны в сигнатурах функций.
Что делают raises и check в hello world?
raises и check в hello world?raises у main объявляет, что функция может упасть. check world.out.write(...) вызывает функцию, которая может провалиться, и если она провалится — пробрасывает ошибку выше, к вызывающему (здесь — рантайму, который выходит с ненулевым статусом). Без check компилятор отказался бы собрать вызов, потому что ошибка осталась бы необработанной.
Какое расширение файлов использует Zero?
Исходные файлы Zero используют расширение .0 (цифра ноль, не буква O). Файл hello.0 — это исходник Zero. Компилятор вызывается командами вроде zero check hello.0 и zero run hello.0.