Встроенные типы
Zero даёт маленький регулярный набор примитивных типов. Ничего экзотического, ничего удивительного — только те, что нужны каждому системному языку, и названы они согласованно.
| Семейство | Типы | Заметки |
|---|---|---|
| Знаковые целые | i8, i16, i32, i64 | Дополнительный код. |
| Беззнаковые целые | u8, u16, u32, u64 | Только 0 и положительные. |
| Размера указателя | usize, isize | Разрядность совпадает с указателем платформы. |
| Плавающие | f32, f64 | IEEE-754. |
| Булев | bool | true или false. |
| Символ | char | Один скаляр Unicode. |
| Строка | String | UTF-8 строка. |
| Пустой | Void | «Нет полезного значения». |
Это полный список примитивов, которыми вы будете пользоваться каждый день. Составные типы — shapes, enums, choices — строятся из них.
Целые
Целочисленные типы следуют единообразному шаблону именования: i для знаковых, u для беззнаковых, дальше — разрядность. То есть i32 — это 32-битное знаковое целое; u8 — беззнаковый байт; i64 — 64-битное знаковое.
let small_signed: i8 = -120
let byte: u8 = 250
let id: i32 = 1
let big: i64 = 9_000_000_000
let index: usize = 0
По умолчанию для литерала без суффикса — i32, если только окружающий контекст не вынуждает иное:
let answer = 42 // i32
Когда нужна конкретная разрядность, прикрепите суффикс к литералу или аннотируйте привязку:
let byte = 250_u8 // типизированный литерал
let byte: u8 = 250 // типизированная привязка
Обе формы дают одно и то же значение. Форма с суффиксом литерала удобна, когда вы передаёте литерал напрямую в функцию или строите структуру:
let pair: BytePair = Pair { left: 1_u8, right: 2_u8 }
Когда какая разрядность
Короткое правило:
i32для большинства знаковой арифметики. Достаточно широк почти для всего, что вы считаете; быстрый на всех платформах.u8для байтовой работы. Байты из файла, байты в буфере, байты по сети.u32/u64для неотрицательных счётчиков, когда важен диапазон. Смещения в файле больше 2 ГБ, большие счётчики.usizeдля размеров и индексов. Размером с указатель — совпадает с тем, что платформа использует для адресации памяти.i64для времени-с-эпохи и подобного. Достаточно большой для наносекунд на сотни лет.
Выбирать самый маленький подходящий тип — хорошая практика; выбрать слишком маленький и переполниться — гораздо большая проблема, чем выбрать на бит шире нужного.
Булевы
let ok = true
let done: bool = false
У bool ровно два значения: true и false. Это литералы, а не константы, которые откуда-то импортируют. Условие в if или while — это bool; никакой неявной truthiness для целых или строк.
if ok {
check world.out.write("yes\n")
} else {
check world.out.write("no\n")
}
If/else разбирает условия подробно.
Плавающие
f32 и f64 — это 32-битные и 64-битные IEEE-754 числа с плавающей точкой соответственно. Используйте их, когда нужны дробные значения — измерения, отношения, геометрия. Для точной арифметики над деньгами предпочитайте целые в наименьшей единице (центы, сатоши), а не плавающие.
let ratio: f32 = 0.5
let pi: f64 = 3.141592653589793
f64 — это умолчание для литералов плавающих без суффикса.
Символы и строки
char содержит одно скалярное значение Unicode:
let initial: char = 'Z'
String — это последовательность символов, обычно закодированная в UTF-8 стандартной библиотекой. Строковые литералы используют двойные кавычки:
let message: String = "hello from zero\n"
Привычные escape-последовательности работают — \n для перевода строки, \t для табуляции, \\ для литерального обратного слэша, \" для литеральной двойной кавычки.
let multi_line = "line one\nline two\n"
Стандартная библиотека выставляет байтовые представления строки для низкоуровневой работы. Форма std.mem.span("zero") возвращает Span<u8> по байтам — пригодится, когда вы парсите, хэшируете или сравниваете по байтам.
Void
Void — это «нет полезного возвращаемого значения» в Zero. Функции, существующие ради побочных эффектов, его используют:
pub fun main(world: World) -> Void raises {
check world.out.write("hello\n")
}
main что-то пишет и возвращается. Значения отдавать обратно нечего, поэтому тип — Void. Void встретится у большинства функций, которые трогают World — их выбирают за эффект, а не за результат.
Подчёркивания в числовых литералах
Длинные числовые литералы могут использовать подчёркивания как визуальные разделители. Компилятор их игнорирует, поэтому это чисто читательская фича:
let big = 9_000_000_000_i64
let bytes = 1_048_576_u32 // 1 MiB
Используйте их везде, где цифры становится сложно считать.
Шпаргалка по типизированным суффиксам литералов
| Суффикс | Тип | Пример |
|---|---|---|
_i8 / _i16 / _i32 / _i64 | Знаковое целое | 127_i8 |
_u8 / _u16 / _u32 / _u64 | Беззнаковое целое | 255_u8 |
_usize / _isize | Размера указателя | 0_usize |
_f32 / _f64 | Плавающее | 0.5_f32 |
Тянитесь к ним, когда конструируете значение там, где окружающий контекст не фиксирует тип.
Дальше: функции
Примитивы бесполезны без того, что с ними делать. Следующая статья разбирает функции в Zero — как их объявлять, возвращать из них значения и собирать вместе для построения настоящих программ.
Часто задаваемые вопросы
Какие примитивные типы есть в Zero?
Zero поставляется со знаковыми целыми i8, i16, i32, i64; беззнаковыми u8, u16, u32, u64; целыми размера указателя usize и isize; плавающими f32 и f64; bool; char; String; и Void для функций, не возвращающих ничего полезного.
Какой тип целых по умолчанию в Zero?
Целочисленный литерал без суффикса вроде 42 по умолчанию имеет тип i32, если контекст не вынуждает другой тип. Чтобы использовать конкретную разрядность, пишите литерал с суффиксом 42_u8 или 42_i64, либо аннотируйте тип привязки явно: let count: u8 = 42.
Есть ли в Zero отдельный строковый тип?
Да. Строковые литералы вроде "hello" имеют встроенный строковый тип, который стандартная библиотека трактует как последовательность байт (обычно UTF-8). Для низкоуровневой работы с байтами библиотека выставляет span и байтовые утилиты; для посимвольных операций есть char для отдельных скалярных значений.
Что означает Void в Zero?
Void — это возвращаемый тип функции, которая не производит полезного значения. Она существует ради побочных эффектов. Привычная сигнатура pub fun main(world: World) -> Void raises использует Void, потому что main существует, чтобы делать I/O и выйти, а не чтобы производить значение.
В чём разница между i32 и u32 в Zero?
i32 — знаковое 32-битное целое с диапазоном от −2 147 483 648 до 2 147 483 647. u32 — беззнаковое с диапазоном от 0 до 4 294 967 295. Знаковые типы — когда отрицательные значения имеют смысл, беззнаковые — когда отрицательное было бы багом: для счётчиков, индексов, размеров и так далее.