diff --git a/src/ch01.md b/src/ch01.md index 35bb4f3..2102ae5 100644 --- a/src/ch01.md +++ b/src/ch01.md @@ -57,7 +57,7 @@ zig run ex-ch01-01.zig При импортировании модуля нужно указать его имя. Стандартная библиотека Zig доступна по имени `std`. Чтобы импортировать какой-то конкретный файл, нужно использовать -путь относительно того файла, в котором делается имортирование. Например, мы могли +путь относительно того файла, в котором делается импортирование. Например, мы могли бы поместить описание структуры `User` в отдельный файл (скажем, `models/user.zig`) и тогда бы в основном файле мы бы написали @@ -81,7 +81,7 @@ pub const User = struct { }; ``` -И тогда бы могли в главном файле имортировать обе сущности: +И тогда бы могли в главном файле импортировать обе сущности: ``` const user = @import("models/user.zig"); @@ -91,11 +91,11 @@ const MAX_POWER = user.MAX_POWER; Скорее всего, на данный момент у Вас больше вопросов, чем ответов. Что такое `user` в приведенном отрывке? Хотя мы ещё не знакомы с ключевым -словом `var`, но тем не менее можно спросить, а что если вместо `const` +словом `var`, но тем не менее можно спросить, а что, если вместо `const` использовать `var`? Или. возможно, у Вас возник вопрос по поводу использования сторонних библиотек. Это всё хорошие вопросы, но чтобы ответить на них, -нам нужно глубже изучить Zig, а пока нам придётся смириться с тем, что мы уже -знаем: +нам нужно глубже изучить Zig, а пока нам придётся обойтись тем, что мы уже +знаем, а именно: * как импортировать стандартную библиотеку (`const std = @import("std");`) * как импортировать свои собственные файлы (`const user = @import(models/user.zig)`) @@ -154,23 +154,98 @@ fn add(a: i64, b: i64) i64 { } ``` -Программисты, пишущие на языках C или C++ наверняка заметят, что Zig +Программисты, пишущие на языках C или C++, наверняка заметят, что Zig не требует объявления/определения функции до её использования, функция `add` вызывается раньше (по тексту), чем встречается её определение. -Далее отметит тип `i64`. Вот некоторые другие целочисленные/вещественные типы: +Далее отметим тип `i64`. Вот некоторые другие целочисленные/вещественные типы: `u8`, `i8`, `u16`, `i16`, `u32`, `i32`, `u47`, `i47`, `u64`, `i64`, `f32` and `f64`. Наличие в списке `u47` и `i47` это вовсе не проверка того, что Вы ещё не спите - Zig умеет работать с целыми числами произвольного размера (в битах). Возможно, -ВЫ не будете использовать такие типы (`u1`, `s9` и т.п.), однако, иногда +Вы не будете использовать такие типы (`u1`, `s9` и т.п.), однако, иногда они удобны или даже необходимы. Тип, который Вы точно будете часто использовать, это `usize` - это целочисленный тип размером с указатель (для данной платформы) и это тип представляет длину/размер чего-либо. -Давайте +Давайте (без всякой на то причины) изменим реализацию функции `add` вот таким +образом: +```zig +fn add(a: i64, b: i64) i64 { + a += b; + return a; +} +``` +Мы получим ошибку в строчке, где `a += b`, "нельзя присваивать значение константе". +Это важное наблюдение, к которому мы ещё вернёмся позже: параметры функций являются +константами. +В Zig, ради лучшей читабельности, нет перегрузки функций, то есть нельзя сделать +несколько функций с одинаковыми именами, но с разными типами параметров +или с разным их количеством. На данный момент это всё, что нам нужно знать про функции. +## Структуры +Далее в нащем примере идёт создание экземпляра структуры `User`, +определение которой располагается после функции `main` и которое гласит: + +```zig +pub const User = struct { + power: u64, + name: []const u8, +}; +``` +Поскольку эта структура у нас используется только в том же файле, где и +определена, то слово `pub` тут необязательно. Оно было использовано для +того, чтобы ознакомиться с экспортом определений. + +Поля структуры оканчиваются запятой (в отличие от С) и им можно присвоить +значение по умолчанию (также в отличие от С): + +```zig +pub const User = struct { + power: u64 = 0, + name: []const u8, +}; +``` + +Когда мы создаём экземпляр структуры, *все* её поля должны быть проинициализированы. +Например, если использовать наше первоначальное определение структуры `User` +(у которой поле `power` не имеет значения по умолчанию) и написать + +``` +const user = User{.name = "Пётр"}; +``` +то мы получим ошибку, в которой будет сообщено, что поле `power` отсутствует. +Если же использовать определение, в котором для поля `power` заданом значение по умолчанию, +то тогда такой код успешно откомпилируется. + +Структуры могут иметь методы, они могут содержать определения (включая другие структуры), +а также могут быть вообще пустыми (и в таком случае они работают как пространства имён). + +```zig +pub const User = struct { + power: u64 = 0, + name: []const u8, + + pub const SUPER_POWER = 9000; + + fn diagnose(user: User) void { + if (user.power >= SUPER_POWER) { + std.debug.print("Вот это силища, больше, чем {d}!!!", .{SUPER_POWER}); + } + } +}; +``` + +Методы это просто обычные функции, которые можно вызвать, используя точку: + +```zig +// вызвать функцию diagnose для некоторого экземпляра User +user.diagnose(); + +// предыдущая строчка это "синтаксический сахар" для вот такой полной формы: +User.diagnose(user); +```