Ах, Zig — язык, который заставляет C выглядеть так, будто он спит с 70-х годов. Давайте закатаем рукава и разберём этого современного претендента на системное программирование, дополненного примерами кода, которые действительно компилируются, и аналогиями, от которых не будет вас коробить (почти).

Первый контакт: установка бензопилы

Прежде чем мы будем жонглировать указателями памяти, давайте заточим наши инструменты. Создайте файл hello.zig:

const std = @import("std");
pub fn main() void {
    std.debug.print("Привет, Meatbag!\n", .{});
}

Скомпилируйте с помощью zig build-exe hello.zig и запустите с помощью ./hello. Поздравляем — вы только что написали более безопасный системный код, чем 90% инженеров NASA 1970-х. Точка в операторе печати не является опечаткой — это пустой кортеж, способ Zig сказать «я понял».

Управление памятью: балет с бензопилами

Ручное управление памятью в Zig похоже на то, как если бы дать ребёнку скальпель — ужасающе мощно. Давайте выделим ресурсы ответственно:

const std = @import("std");
pub fn main() !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = arena.allocator();
    const blood_pressure = try allocator.alloc(u8, 3);
    defer allocator.free(blood_pressure);
    blood_pressure = 240;
    std.debug.print("Sys: {}\n", .{blood_pressure});
}

Этот шаблон распределителя арены похож на наличие уборщицы памяти — она автоматически убирает после вашей вечеринки с помощью defer. Тип возвращаемого значения !void — способ Zig сказать: «Это может не получиться, но мы здесь взрослые люди».

Система типов: строгие родители приветствуются

Система типов Zig не терпит дураков. Посмотрим на приведение типов в действии:

const std = @import("std");
pub fn main() void {
    var counter: u8 = 0;
    // Это приведёт к сбою вашей программы:
    // counter = 256;
    std.debug.print("Счётчик: {}\n", .{counter});
}

Раскомментируйте строку 6 и наблюдайте, как Zig ударяет вас по запястью во время компиляции. В отличие от подхода C «на ваше усмотрение», Zig обеспечивает явные преобразования — эквивалент проверки ID на входе.

Система сборки: никаких кошмаров с Makefile

Система сборки Zig похожа на инструкции IKEA — удивительно приятная. Создайте build.zig:

const std = @import("std");
pub fn build(b: *std.Build) void {
    const exe = b.addExecutable(.{
        .name = "zombie-apocalypse",
        .root_source_file = .{ .path = "mad_scientist.zig" },
    });
    b.installArtifact(exe);
}

Теперь запустите zig build install, чтобы получить свой двоичный файл в zig-out/bin. Хотите кросс-компиляцию? Добавьте:

exe.setTarget(.{
    .cpu_arch = .aarch64,
    .os_tag = .linux,
});

Бум — двоичные файлы ARM64 Linux с вашего тостера. Система сборки настолько проста, что заставляет CMake выглядеть как машина Рубе Голдберга.

graph TD Source["./src/main.zig"] --> Build["build.zig"] Build -->|zig build| Artifact[Executable] Artifact -->|Run| Output["Консольный вывод"] Build -->|Кросс-компиляция| Windows[".exe"] Build -->|Кросс-компиляция| Linux[ELF]

Взаимодействие: надоедливый младший брат C

Нужно поговорить с библиотеками C? Zig не просто взаимодействует — он прямо-таки устраивает быстрые свидания:

const c = @cImport({
    @cInclude("SDL2/SDL.h");
});
pub fn main() void {
    _ = c.SDL_Init(c.SDL_INIT_VIDEO);
    defer c.SDL_Quit();
    const window = c.SDL_CreateWindow(
        "Ziggy Stardust",
        0, 0, 640, 480,
        c.SDL_WINDOW_SHOWN
    );
}

Система импорта C в Zig настолько плавная, что это всё равно что узнать, что ваш бывший всё ещё хочет дружить. Директива @cImport автоматически обрабатывает перевод заголовков — никаких генераторов привязки не требуется.

Обработка ошибок: ожидайте неожиданного

Zig относится к ошибкам как к полноправным участникам, а не как к надоедливым гостям:

const std = @import("std");
fn explode() !void {
    return error.Kaboom;
}
pub fn main() void {
    explode() catch |err| {
        std.debug.print("Ошибка: {s}\n", .{@errorName(err)});
    };
}

Тип возвращаемого значения !void представляет собой объединение ошибок — либо успех, либо тег ошибки. Блоки catch позволяют вам обрабатывать ошибки, как чрезмерно опекающий родитель.

Философия Zig: меньше помощи, больше мощности

В то время как такие языки, как Rust, заворачивают вас в пузырчатую плёнку, Zig вручает вам огнемёт и говорит: «Не направляйте его себе в лицо». Он идеально подходит для:

  • Встраиваемых систем, где каждый байт имеет значение;
  • Высокопроизводительных игровых движков;
  • Разработки ОС;
  • Замены C без экзистенциального страха. Стандартная библиотека намеренно минималистична — ожидается, что вы принесёте свои собственные инструменты на вечеринку. Учебные ресурсы, такие как Ziglings и справочник по языку, — ваши новые лучшие друзья. Вот и всё — Zig во всей своей непримиримой низкоуровневой красе. Он не будет держать вас за руку, но даст вам достаточно верёвки, чтобы построить подвесной мост… или повеситься. Выбирайте мудро.