On branch main

modified:   src/ch02.md
Untracked files:
src/ch03.md
This commit is contained in:
zed
2023-11-14 15:57:43 +03:00
parent 310d50f632
commit 57185a1f1a

View File

@@ -3,7 +3,8 @@
В этой главе мы рассмотрим то, что было опущено в предыдущей -
инструкции управления выполнением программы, а также типы данных,
о которых мы ещё не упоминали (объединения и ошибки).
о которых мы ещё не упоминали - перечисления, объединения и ошибки,
как особый вид перечислений.
## Управление потоком выполнения
@@ -25,7 +26,7 @@
слова `and` и `or`, а не "комбинации закорючек".
Далее, оператор сравнения (`==`) не работает для срезов, например, для строк (`[]const u8`).
В большинстве случаев для сравнения Вы будете использовать `std.mem.eql(u8, str1, str2)`,
В большинстве случаев для сравнения используется функция `std.mem.eql(u8, str1, str2)`,
которая сначала сравнивает длины срезов, а потом побайтно их содержимое.
Операторы `if`, `else if`, `else` в Zig ничем особо не примечательны:
@@ -251,7 +252,7 @@ const personality_analysis = blk: {
Блоки подобного рода нужно оканчивать точкой с запятой.
Позже, когда мы будем изучать объединения с пометками,
Позже, когда мы будем изучать маркированные объединения,
объединения-ошибки и типы с необязательным значением,
мы узнаем, какие ещё возможности предоставляют управляющие структуры.
@@ -269,7 +270,7 @@ const Status = enum {
};
```
И. как и структуры, перечисления могут содержать другие определения,
Так же, как и структуры, перечисления могут содержать другие определения,
включая функции, которые в качестве аргумента могут использовать
перечисление, в которое они входят (а могут и не использовать):
@@ -539,12 +540,13 @@ pub fn main() OpenError!void {
}
```
Это называется объединение-ошибка (error unon type) и означает,
Комбинация `<error-set>!<return-type>` это такой составной тип,
объединение с ошибкой (error union type) и это означает,
что наша `main` может вернуть *или* ошибку *или* что-то (ну, в данном случае ничто, `void`).
До этого момента мы были предельно явными: мы описали
специальный набор возможных ошибок и использовали его в возвращаемом значении.
Однако, когда дело касается ошибок, у Zig имеется пара классных "трюков".
Во-первых, вместо того, чтобы писать `<error-set!<return-type>>`,
Во-первых, вместо того, чтобы писать `<error-set>!<return-type>`,
можно написать просто `!<return-type>` и тогда компилятор сам выведет
набор ошибок, который функция может в принципе вернуть. Так что можно писать так:
@@ -563,11 +565,11 @@ pub fn main() !void {
На самом деле оба подхода (с явным указанием всего и без такового) не вполне
эквивалентны. Например, ссылки на функции с неявным набором ошибок требуют
специального типа, `anyerror`. Разработчики библиотек, возможно, предпочитают
быть более явными, так код становиится самодокументирующимся. Тк или иначе,
оба подхода имеют право на существаание и Вы можете использовать оба
быть более явными, так код становиится самодокументирующимся. Так или иначе,
оба подхода имеют право на существование и Вы можете использовать оба
по своему усмотрению.
Реальная ценность объединений-ошибок проявляется при обработке ошибок,
Реальная ценность объединений с ошибками проявляется при обработке ошибок,
для которой в Zig есть ключевые слова `catch` и `try` (но только это совсем
не такие `try/catch/finally`, как в других языках программирования).
После вызова функции, которая может вернуть ошибку, можно использовать
@@ -620,19 +622,69 @@ try action(req, res);
Это полезно в частности потому, что **ошибки должны быть обработаны**.
По большей части Вы будете использовать для этого `catch` или `try`,
но объединения-ошибки также поддерживаются операторами `if` и `while`,
но объединения с ошибками также поддерживаются операторами `if` и `while`,
вполне аналогично тому, как они работают с опциональными значениями.
В случае `while`, если условие сразу же даёт ошибку, исполняется оборот `else`.
Имеется также специальный тип `anyerror`, в котором может содержаться
любая ошибка. Хоть мы и можем задать тип возвращаемого из функции
значения как в виде `anyerror!<ype>`, так и в виде `!<type>`, эти
значения как в виде `anyerror!<type>`, так и в виде `!<type>`, эти
две формы не являются эквивалентными. Выведенный набор ошибок создаётся
на основе конкретных ошибок, возвращаемых функций, в то время как
`anyerror` - это глобальный набор ошибок, множество всех ошибок, фигурирующих
в программе.
в программе. Следовательно, использование `anyerror` в сигнатуре
функции это как бы обозначение того, что ваша функция номинально может вернуть
такие ошибки, какие в реальности она вернуть не может.
Тип `anyerror` используется для параметров функций или полей структур,
передаваемых в функцию, когда эта функция способна обрабатывать
любые возможные ошибки (ну, например, функция записи в журнал работы программы)
Довольно часто используется комбинация объединения с ошибкой с опциональным типом.
Если набор ошибок выводится, то это записывается вот так:
```
/ load the last saved game
pub fn loadLast() !?Save {
// TODO
return null;
}
```
Существуют различные способы обрабатывать вызов таких функций,
но наиболее компактный это сначала использовать `try`, чтобы
извлечь ошибку и затем `orelse`, чтобы развернуть необязательное значение,
вот рабочий скелет:
```
const std = @import("std");
pub fn main() void {
// This is the line you want to focus on
const save = (try Save.loadLast()) orelse Save.blank();
std.debug.print("{any}\n", .{save});
}
pub const Save = struct {
lives: u8,
level: u16,
pub fn loadLast() !?Save {
//todo
return null;
}
pub fn blank() Save {
return .{
.lives = 3,
.level = 1,
};
}
};
```
Хотя в Zig имеются некоторые особенности, которые предоставляют нам
ещё более широкие возможности, то, что мы видели в первых двух главах,
уже составляет значительную часть языка. И это будет служить нам базой
при исследовании более сложных тем без отвлечения на синтаксис.