On branch main
modified: src/ch01.md modified: src/ch08.md modified: src/ch09.md new file: src/ex-ch09-01.zig
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
Язык программирования Zig это компилируемый язык со строгой статической
|
||||
типизацией. Он поддерживает обобщённые структуры данных, имеет мощные
|
||||
средства метапрограммирования. Управление памятью в Zig ручное, то есть в
|
||||
нём нет сборки мусора. Многие люди считают Zig современной альтернативой
|
||||
языку C, из которого Zig позаимствовал символ `;` как символ, завершающий
|
||||
нём нет сборки мусора. Многие считают Zig современной альтернативой языку
|
||||
C, из которого Zig позаимствовал символ `;` как символ, завершающий
|
||||
инструкции (statements), а также фигурные скобки как разграничители
|
||||
блоков кода.
|
||||
|
||||
|
||||
@@ -11,12 +11,12 @@
|
||||
не менее, сам по себе язык вполне пригоден для достижения аналогичных
|
||||
целей.
|
||||
|
||||
## Простая реализация интерфейса
|
||||
## Простой интерфейс и его реализация
|
||||
|
||||
Мы сейчас реализуем простой интерфейс, который будет называться `Writer`.
|
||||
Он будет достаточно прост для понимания сути и будет содержать
|
||||
всего одну функцию. Если надо больше, они легко добавляются.
|
||||
Прежде всего, вот сам интерфейс:
|
||||
Он будет достаточно прост для понимания сути и будет содержать всего одну
|
||||
функцию. Если надо больше, они легко добавляются по аналогии. Прежде
|
||||
всего, вот сам интерфейс:
|
||||
|
||||
```zig
|
||||
const Writer = struct {
|
||||
|
||||
79
src/ch09.md
79
src/ch09.md
@@ -1,8 +1,82 @@
|
||||
|
||||
# Программируем на языке Zig
|
||||
|
||||
Теперь, когда большая часть языка рассмотрена, мы подытожим наши знания,
|
||||
возвращаясь по мере необходимости к уже знакомым темам, а также
|
||||
познакомимся с некоторыми практическими аспектами использования Zig.
|
||||
|
||||
## Снова висячие указатели
|
||||
|
||||
Начнём с рассмотрения ещё нескольких примеров висячих указателей.
|
||||
Может показаться странным, что мы опять к этому возвращаемся,
|
||||
однако, если ранее Вы использовали только языки со сборкой мусора,
|
||||
то, скорее всего, висячие указатели будут вызывать наибольшие трудности
|
||||
из тех, с которыми Вы будете сталкиваться.
|
||||
|
||||
Сможете догадаться, что напечатает следующий пример?
|
||||
|
||||
```zig
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var lookup = std.StringHashMap(User).init(allocator);
|
||||
defer lookup.deinit();
|
||||
|
||||
const goku = User{.power = 9001};
|
||||
|
||||
try lookup.put("Goku", goku);
|
||||
|
||||
// returns an optional, .? would panic if "Goku"
|
||||
// wasn't in our hashmap
|
||||
const entry = lookup.getPtr("Goku").?;
|
||||
|
||||
std.debug.print("Goku's power is: {d}\n", .{entry.power});
|
||||
|
||||
// returns true/false depending on if the item was removed
|
||||
_ = lookup.remove("Goku");
|
||||
|
||||
std.debug.print("Goku's power is: {d}\n", .{entry.power});
|
||||
}
|
||||
|
||||
const User = struct {
|
||||
power: i32,
|
||||
};
|
||||
```
|
||||
|
||||
Запустим:
|
||||
|
||||
```
|
||||
$ /opt/zig-0.11/zig run src/ex-ch09-01.zig
|
||||
Goku's power is: 9001
|
||||
Goku's power is: -1431655766
|
||||
```
|
||||
|
||||
В этом примере мы знакомимся с обобщённой хэш-таблицей
|
||||
(`std.StringHashMap`), которая является специализилванной версией
|
||||
`std.AutoHashMap` с типом ключа `[]const u8`. Даже если не уверены на все
|
||||
сто относительно того, что конкретно происходит при выводе, наверняка Вы
|
||||
поняли, что это однозначно связано с тем, что второй вызов `print`
|
||||
делается *после* того, как мы уже удалили элемент из таблицы. Если убрать
|
||||
вызов `remove`, всё будет нормально.
|
||||
|
||||
Чтобы полностью понимать этот пример, нужно чётко представлять себе,
|
||||
*где* находятся данные или, иными словами, кто ими *владеет*. Как мы
|
||||
знаем, аргументы в функцию передаются по значению, то есть мы передаём
|
||||
копию (возможно, поверхностную) значения переменной. Экземпляр `User` в
|
||||
таблице `lookup` и `user` находятся в разных местах памяти, то есть в
|
||||
этом коде у нас **два** пользователя, каждый со своим "владельцем".
|
||||
`goku` находится во владении у функции `main`, а его копией владеет сама
|
||||
таблица `lookup`.
|
||||
|
||||
Метод `getPtr` возвращает указатель на экземпляр в таблице (`*User` в нашем примере).
|
||||
Собственно, в этом и "проблема", после вызова `remove` указатель
|
||||
`entry` перестаёт показывать в правильное место. В примере у нас
|
||||
`getPtr` и `remove` расположены в тексте близко друг к другу,
|
||||
поэтому практически очевидно, в чём тут ошибка.
|
||||
|
||||
## Владение
|
||||
|
||||
## `ArrayList`
|
||||
@@ -14,8 +88,3 @@
|
||||
## Система сборки
|
||||
|
||||
## Сторонние зависимости
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
29
src/ex-ch09-01.zig
Normal file
29
src/ex-ch09-01.zig
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub fn main() !void {
|
||||
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
|
||||
const allocator = gpa.allocator();
|
||||
|
||||
var lookup = std.StringHashMap(User).init(allocator);
|
||||
defer lookup.deinit();
|
||||
|
||||
const goku = User{.power = 9001};
|
||||
|
||||
try lookup.put("Goku", goku);
|
||||
|
||||
// returns an optional, .? would panic if "Goku"
|
||||
// wasn't in our hashmap
|
||||
const entry = lookup.getPtr("Goku").?;
|
||||
|
||||
std.debug.print("Goku's power is: {d}\n", .{entry.power});
|
||||
|
||||
// returns true/false depending on if the item was removed
|
||||
_ = lookup.remove("Goku");
|
||||
|
||||
std.debug.print("Goku's power is: {d}\n", .{entry.power});
|
||||
}
|
||||
|
||||
const User = struct {
|
||||
power: i32,
|
||||
};
|
||||
Reference in New Issue
Block a user