Сравнение с ручной памятью C и Rust
Ставим подход Zig к памяти рядом с C и Rust, чтобы понять его нишу.
Ручная безопасность в Zig — это компромисс: язык не доказывает корректность памяти, как Rust, но делает выделения и освобождения настолько явными и инструментированными, что ошибки легко находить.
У трёх системных языков три разные философии памяти. C даёт полный ручной контроль без страховки. Rust доказывает безопасность памяти на этапе компиляции ценой строгих правил. Zig занимает середину: ручное управление, как в C, но с явностью и инструментами, которые ловят большинство ошибок.
C: malloc/free и тишина
В C вы зовёте malloc и free вручную. Компилятор не следит за временем жизни: забытый free — утечка, лишний free — двойное освобождение, free + использование — висячий указатель. Эти ошибки молчат до краха в продакшене. C полностью доверяет программисту и ничем не помогает.
Rust: borrow checker доказывает безопасность
Rust идёт в другую крайность: его borrow checker на этапе компиляции доказывает, что висячих указателей и гонок данных нет. Это мощно, но требует переучиться: концепции владения, заимствования и времён жизни добавляют когнитивную нагрузку, а некоторые корректные программы borrow checker отвергает, требуя обходных приёмов.
Zig: явность плюс инструменты
// Zig: владение видно глазами через явный аллокатор и defer
fn process(alloc: std.mem.Allocator) !void {
const data = try alloc.alloc(u8, 256);
defer alloc.free(data); // освобождение рядом с выделением
// borrow checker'а нет — за корректность отвечаете вы,
// но GPA поймает утечку, а safe-сборка — выход за границы
}
Zig не доказывает безопасность памяти, как Rust. Зато он делает её обозримой: аллокатор явный, освобождение пишется рядом через defer, отладочный аллокатор ловит утечки, а safe-сборка ловит выход за границы и use-after-free в режиме отладки. Вы отвечаете за корректность сами, но язык даёт мощную страховочную сетку и не заставляет переучивать мышление.
Как работает под капотом
Отсутствие borrow checker означает, что компилятор Zig не строит граф времён жизни и не отвергает программы из-за заимствований. Безопасность достигается рантайм-проверками в safe-сборках (границы срезов, переполнения) и инструментами вроде GPA. В ReleaseFast проверки снимаются — как в C, ради максимальной скорости. Это сознательный выбор: простота языка в обмен на ручную ответственность.
Частые ошибки
Первая — ждать от Zig гарантий Rust: borrow checker'а здесь нет, висячий указатель возможен. Вторая — отлаживать память в ReleaseFast, где защита отключена; ищите ошибки в safe-режиме. Третья — считать Zig «небезопасным как C»: инструменты и явность ловят куда больше, чем голый C.
Итог
- C: ручная память без страховки — молчаливые утечки и висячие указатели.
- Rust: borrow checker доказывает безопасность ценой сложности и переучивания.
- Zig: ручное управление, но явное и инструментированное — золотая середина.
- В Zig за корректность отвечаете вы, но GPA и safe-сборка дают сильную страховку.