On branch main
modified: src/ch02.md Untracked files: src/ch03.md
This commit is contained in:
82
src/ch02.md
82
src/ch02.md
@@ -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 имеются некоторые особенности, которые предоставляют нам
|
||||
ещё более широкие возможности, то, что мы видели в первых двух главах,
|
||||
уже составляет значительную часть языка. И это будет служить нам базой
|
||||
при исследовании более сложных тем без отвлечения на синтаксис.
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user