On branch main
modified: src/ch09.md new file: src/ex-ch09-06.zig
This commit is contained in:
98
src/ch09.md
98
src/ch09.md
@@ -403,14 +403,14 @@ Zig нет свойств (это такие поля структуры/кла
|
||||
символ `_` в качестве первого символа имен тех полей, которые
|
||||
предназначены только для внутреннего использования.
|
||||
|
||||
Поскольку строки имеют тип `[]8` или `[]const u8`, список из байтов
|
||||
(то есть `ArrayList(u8)`) это подходящий тип для построения
|
||||
конструктора строк по типу `StringBuilder` в .NET или `strings.Builder` в Go.
|
||||
Поскольку строки имеют тип `[]8` или `[]const u8`, список из байтов (то
|
||||
есть `ArrayList(u8)`) это подходящий тип для построения конструктора
|
||||
строк по типу `StringBuilder` в .NET или `strings.Builder` в Go.
|
||||
Фактически, вы будете часто использовать в случаях, когда функция
|
||||
приниммает `Writer` и вам на выходе нужна строка. Ранее мы видели пример,
|
||||
в котором для вывода документа JSON на стандартный вывод
|
||||
использовалась `std.json.stringify`. Вот пример использования
|
||||
`ArrayList(u8)` для вывода в переменную:
|
||||
в котором для вывода документа JSON на стандартный вывод использовалась
|
||||
`std.json.stringify`. Вот пример использования `ArrayList(u8)` для вывода
|
||||
в переменную:
|
||||
|
||||
```zig
|
||||
const std = @import("std");
|
||||
@@ -434,6 +434,92 @@ pub fn main() !void {
|
||||
|
||||
## `anytype`
|
||||
|
||||
Мы уже вскользь упоминали `anytype` в первой главе. Такой "тип" это
|
||||
весьма полезеная форма утиной (неявной) типизации во время компиляции.
|
||||
Вот простой логгер:
|
||||
|
||||
```zig
|
||||
pub const Logger = struct {
|
||||
level: Level,
|
||||
|
||||
// "error" is reserved, names inside an @"..." are always
|
||||
// treated as identifiers
|
||||
const Level = enum {
|
||||
debug,
|
||||
info,
|
||||
@"error",
|
||||
fatal,
|
||||
};
|
||||
|
||||
fn info(logger: Logger, msg: []const u8, out: anytype) !void {
|
||||
if (@intFromEnum(logger.level) <= @intFromEnum(Level.info)) {
|
||||
try out.writeAll(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Параметр `out` метода `info` имеет тип `anytype`.
|
||||
Это означает, что `Logger` может использовать
|
||||
любую структуру, у которой есть метод `writeAll`,
|
||||
у которого на входе `[]const u8` и на выходе `!void`.
|
||||
Проверка типов производится во время компиляции
|
||||
(а не во время выполнения программы): для каждого
|
||||
типа, использованного в качестве второго параметра `Logger.info`,
|
||||
проверяется, есть ли у этого типа метод `writeAll`.
|
||||
Если мы попытаемся вызвать `info` с типом, который
|
||||
не имеет всех нужных функций (в нашем случае одной),
|
||||
то мы получим ошибку компиляции:
|
||||
|
||||
```zig
|
||||
var l = Logger{.level = .info};
|
||||
try l.info("sever started", true);
|
||||
```
|
||||
|
||||
Компилятор скажет, что у типа `bool` нет поля с именем `writeAll`.
|
||||
Использование `writer` типа `ArrayList(u8)` (например) работает:
|
||||
|
||||
```zig
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var l = Logger{.level = .info};
|
||||
|
||||
var arr = std.ArrayList(u8).init(allocator);
|
||||
defer arr.deinit();
|
||||
|
||||
try l.info("sever started", arr.writer());
|
||||
std.debug.print("{s}\n", .{arr.items});
|
||||
}
|
||||
```
|
||||
|
||||
Одним из существенных недостатков типа `anytype` является документация.
|
||||
Давайте взглянем на сигнатуру функции `std.json.stringify`, которую мы
|
||||
уже несколько раз использовали:
|
||||
|
||||
```zig
|
||||
// I **hate** multi-line function definitions
|
||||
// But I'll make an exception for a guide which
|
||||
// you might be reading on a small screen.
|
||||
|
||||
fn stringify(
|
||||
value: anytype,
|
||||
options: StringifyOptions,
|
||||
out_stream: anytype
|
||||
) @TypeOf(out_stream).Error!void
|
||||
```
|
||||
|
||||
Первый параметр, `value: anytype` вроде как очевиден: это что-то, что
|
||||
нужно сериализовать и это что-то может быть чем угодно (на самом деле в
|
||||
Zig существуют некоторые вещи, которые сериализатор JSON сериализовать не
|
||||
сможет). А вот что касается третьего параметра, то, конечно, мы можем
|
||||
догадываться, что это то, *куда* будет выведен документ, но для того,
|
||||
чтобы понять, какие у этой сущности должны быть методы, нужно или глядеть
|
||||
в исходный текст `stringify` или передать что-то первое под руку
|
||||
попавшееся и использовать в качестве документации текст ошибок
|
||||
компиляции.
|
||||
|
||||
## `@typeOf`
|
||||
|
||||
## Система сборки
|
||||
|
||||
34
src/ex-ch09-06.zig
Normal file
34
src/ex-ch09-06.zig
Normal file
@@ -0,0 +1,34 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub const Logger = struct {
|
||||
level: Level,
|
||||
|
||||
// "error" is reserved, names inside an @"..." are always
|
||||
// treated as identifiers
|
||||
const Level = enum {
|
||||
debug,
|
||||
info,
|
||||
@"error",
|
||||
fatal,
|
||||
};
|
||||
|
||||
fn info(logger: Logger, msg: []const u8, out: anytype) !void {
|
||||
if (@intFromEnum(logger.level) <= @intFromEnum(Level.info)) {
|
||||
try out.writeAll(msg);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var l = Logger{.level = .info};
|
||||
|
||||
var arr = std.ArrayList(u8).init(allocator);
|
||||
defer arr.deinit();
|
||||
|
||||
try l.info("sever started", arr.writer());
|
||||
std.debug.print("{s}\n", .{arr.items});
|
||||
}
|
||||
Reference in New Issue
Block a user