zig-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Zig Best Practices

Zig 最佳实践

Type-First Development

类型优先开发

Types define the contract before implementation. Follow this workflow:
  1. Define data structures - structs, unions, and error sets first
  2. Define function signatures - parameters, return types, and error unions
  3. Implement to satisfy types - let the compiler guide completeness
  4. Validate at comptime - catch invalid configurations during compilation
类型在实现前就定义好契约。遵循以下工作流程:
  1. 定义数据结构 - 先定义结构体、联合类型和错误集
  2. 定义函数签名 - 参数、返回类型和错误联合类型
  3. 按类型要求实现 - 让编译器引导你完成完整实现
  4. 编译时验证 - 在编译阶段捕获无效配置

Make Illegal States Unrepresentable

让非法状态无法被表示

Use Zig's type system to prevent invalid states at compile time.
Tagged unions for mutually exclusive states:
zig
// Good: only valid combinations possible
const RequestState = union(enum) {
    idle,
    loading,
    success: []const u8,
    failure: anyerror,
};

fn handleState(state: RequestState) void {
    switch (state) {
        .idle => {},
        .loading => showSpinner(),
        .success => |data| render(data),
        .failure => |err| showError(err),
    }
}

// Bad: allows invalid combinations
const RequestState = struct {
    loading: bool,
    data: ?[]const u8,
    err: ?anyerror,
};
Explicit error sets for failure modes:
zig
// Good: documents exactly what can fail
const ParseError = error{
    InvalidSyntax,
    UnexpectedToken,
    EndOfInput,
};

fn parse(input: []const u8) ParseError!Ast {
    // implementation
}

// Bad: anyerror hides failure modes
fn parse(input: []const u8) anyerror!Ast {
    // implementation
}
Distinct types for domain concepts:
zig
// Prevent mixing up IDs of different types
const UserId = enum(u64) { _ };
const OrderId = enum(u64) { _ };

fn getUser(id: UserId) !User {
    // Compiler prevents passing OrderId here
}

fn createUserId(raw: u64) UserId {
    return @enumFromInt(raw);
}
Comptime validation for invariants:
zig
fn Buffer(comptime size: usize) type {
    if (size == 0) {
        @compileError("buffer size must be greater than 0");
    }
    if (size > 1024 * 1024) {
        @compileError("buffer size exceeds 1MB limit");
    }
    return struct {
        data: [size]u8 = undefined,
        len: usize = 0,
    };
}
Non-exhaustive enums for extensibility:
zig
// External enum that may gain variants
const Status = enum(u8) {
    active = 1,
    inactive = 2,
    pending = 3,
    _,
};

fn processStatus(status: Status) !void {
    switch (status) {
        .active => {},
        .inactive => {},
        .pending => {},
        _ => return error.UnknownStatus,
    }
}
利用Zig的类型系统在编译时防止非法状态。
使用标记联合表示互斥状态:
zig
// Good: only valid combinations possible
const RequestState = union(enum) {
    idle,
    loading,
    success: []const u8,
    failure: anyerror,
};

fn handleState(state: RequestState) void {
    switch (state) {
        .idle => {},
        .loading => showSpinner(),
        .success => |data| render(data),
        .failure => |err| showError(err),
    }
}

// Bad: allows invalid combinations
const RequestState = struct {
    loading: bool,
    data: ?[]const u8,
    err: ?anyerror,
};
显式错误集定义失败模式:
zig
// Good: documents exactly what can fail
const ParseError = error{
    InvalidSyntax,
    UnexpectedToken,
    EndOfInput,
};

fn parse(input: []const u8) ParseError!Ast {
    // implementation
}

// Bad: anyerror hides failure modes
fn parse(input: []const u8) anyerror!Ast {
    // implementation
}
为领域概念使用不同类型:
zig
// Prevent mixing up IDs of different types
const UserId = enum(u64) { _ };
const OrderId = enum(u64) { _ };

fn getUser(id: UserId) !User {
    // Compiler prevents passing OrderId here
}

fn createUserId(raw: u64) UserId {
    return @enumFromInt(raw);
}
编译时验证不变量:
zig
fn Buffer(comptime size: usize) type {
    if (size == 0) {
        @compileError("buffer size must be greater than 0");
    }
    if (size > 1024 * 1024) {
        @compileError("buffer size exceeds 1MB limit");
    }
    return struct {
        data: [size]u8 = undefined,
        len: usize = 0,
    };
}
非穷举枚举实现可扩展性:
zig
// External enum that may gain variants
const Status = enum(u8) {
    active = 1,
    inactive = 2,
    pending = 3,
    _,
};

fn processStatus(status: Status) !void {
    switch (status) {
        .active => {},
        .inactive => {},
        .pending => {},
        _ => return error.UnknownStatus,
    }
}

Module Structure

模块结构

Larger cohesive files are idiomatic in Zig. Keep related code together: tests alongside implementation, comptime generics at file scope, public/private controlled by
pub
. Split only when a file handles genuinely separate concerns. The standard library demonstrates this pattern with files like
std/mem.zig
containing 2000+ lines of cohesive memory operations.
在Zig中,将相关代码集中在较大的内聚文件里是惯用做法。把相关代码放在一起:测试代码与实现代码相邻,编译时泛型放在文件作用域,通过
pub
控制公共/私有访问。只有当文件处理完全无关的功能时才需要拆分。标准库就展示了这种模式,比如
std/mem.zig
包含2000多行内聚的内存操作代码。

Instructions

规范说明

  • Return errors with context using error unions (
    !T
    ); every function returns a value or an error. Explicit error sets document failure modes.
  • Use
    errdefer
    for cleanup on error paths; use
    defer
    for unconditional cleanup. This prevents resource leaks without try-finally boilerplate.
  • Handle all branches in
    switch
    statements; include an
    else
    clause that returns an error or uses
    unreachable
    for truly impossible cases.
  • Pass allocators explicitly to functions requiring dynamic memory; prefer
    std.testing.allocator
    in tests for leak detection.
  • Prefer
    const
    over
    var
    ; prefer slices over raw pointers for bounds safety. Immutability signals intent and enables optimizations.
  • Avoid
    anytype
    ; prefer explicit
    comptime T: type
    parameters. Explicit types document intent and produce clearer error messages.
  • Use
    std.log.scoped
    for namespaced logging; define a module-level
    log
    constant for consistent scope across the file.
  • Add or update tests for new logic; use
    std.testing.allocator
    to catch memory leaks automatically.
  • 使用错误联合类型(
    !T
    )返回带上下文的错误;每个函数要么返回值,要么返回错误。显式错误集可以明确失败模式。
  • 在错误路径上使用
    errdefer
    进行清理;使用
    defer
    进行无条件清理。这样无需try-finally样板代码就能防止资源泄漏。
  • 处理
    switch
    语句中的所有分支;对于真正不可能的情况,可以包含返回错误或使用
    unreachable
    else
    分支。
  • 为需要动态内存的函数显式传递分配器;在测试中优先使用
    std.testing.allocator
    进行泄漏检测。
  • 优先使用
    const
    而非
    var
    ;优先使用切片而非原始指针以保证边界安全。不可变性能明确意图并支持优化。
  • 避免使用
    anytype
    ;优先使用显式的
    comptime T: type
    参数。显式类型能明确意图并生成更清晰的错误信息。
  • 使用
    std.log.scoped
    实现命名空间日志;在文件中定义模块级别的
    log
    常量以保证一致的作用域。
  • 为新逻辑添加或更新测试;使用
    std.testing.allocator
    自动捕获内存泄漏。

Examples

示例

Explicit failure for unimplemented logic:
zig
fn buildWidget(widget_type: []const u8) !Widget {
    return error.NotImplemented;
}
Propagate errors with try:
zig
fn readConfig(path: []const u8) !Config {
    const file = try std.fs.cwd().openFile(path, .{});
    defer file.close();
    const contents = try file.readToEndAlloc(allocator, max_size);
    return parseConfig(contents);
}
Resource cleanup with errdefer:
zig
fn createResource(allocator: std.mem.Allocator) !*Resource {
    const resource = try allocator.create(Resource);
    errdefer allocator.destroy(resource);

    resource.* = try initializeResource();
    return resource;
}
Exhaustive switch with explicit default:
zig
fn processStatus(status: Status) ![]const u8 {
    return switch (status) {
        .active => "processing",
        .inactive => "skipped",
        _ => error.UnhandledStatus,
    };
}
Testing with memory leak detection:
zig
const std = @import("std");

test "widget creation" {
    const allocator = std.testing.allocator;
    var list: std.ArrayListUnmanaged(u32) = .empty;
    defer list.deinit(allocator);

    try list.append(allocator, 42);
    try std.testing.expectEqual(1, list.items.len);
}
为未实现的逻辑返回显式错误:
zig
fn buildWidget(widget_type: []const u8) !Widget {
    return error.NotImplemented;
}
使用try传播错误:
zig
fn readConfig(path: []const u8) !Config {
    const file = try std.fs.cwd().openFile(path, .{});
    defer file.close();
    const contents = try file.readToEndAlloc(allocator, max_size);
    return parseConfig(contents);
}
使用errdefer进行资源清理:
zig
fn createResource(allocator: std.mem.Allocator) !*Resource {
    const resource = try allocator.create(Resource);
    errdefer allocator.destroy(resource);

    resource.* = try initializeResource();
    return resource;
}
带显式默认分支的穷举switch:
zig
fn processStatus(status: Status) ![]const u8 {
    return switch (status) {
        .active => "processing",
        .inactive => "skipped",
        _ => error.UnhandledStatus,
    };
}
带内存泄漏检测的测试:
zig
const std = @import("std");

test "widget creation" {
    const allocator = std.testing.allocator;
    var list: std.ArrayListUnmanaged(u32) = .empty;
    defer list.deinit(allocator);

    try list.append(allocator, 42);
    try std.testing.expectEqual(1, list.items.len);
}

Memory Management

内存管理

  • Pass allocators explicitly; never use global state for allocation. Functions declare their allocation needs in parameters.
  • Use
    defer
    immediately after acquiring a resource. Place cleanup logic next to acquisition for clarity.
  • Prefer arena allocators for temporary allocations; they free everything at once when the arena is destroyed.
  • Use
    std.testing.allocator
    in tests; it reports leaks with stack traces showing allocation origins.
  • 显式传递分配器;绝不为内存分配使用全局状态。函数需在参数中声明其内存分配需求。
  • 获取资源后立即使用
    defer
    。将清理逻辑放在获取资源的代码旁边以提高可读性。
  • 临时内存分配优先使用arena分配器;销毁arena时会一次性释放所有内存。
  • 在测试中使用
    std.testing.allocator
    ;它会通过栈跟踪报告泄漏的内存分配来源。

Examples

示例

Allocator as explicit parameter:
zig
fn processData(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
    const result = try allocator.alloc(u8, input.len * 2);
    errdefer allocator.free(result);

    // process input into result
    return result;
}
Arena allocator for batch operations:
zig
fn processBatch(items: []const Item) !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = arena.allocator();

    for (items) |item| {
        const processed = try processItem(allocator, item);
        try outputResult(processed);
    }
    // All allocations freed when arena deinits
}
将分配器作为显式参数:
zig
fn processData(allocator: std.mem.Allocator, input: []const u8) ![]u8 {
    const result = try allocator.alloc(u8, input.len * 2);
    errdefer allocator.free(result);

    // process input into result
    return result;
}
使用arena分配器处理批量操作:
zig
fn processBatch(items: []const Item) !void {
    var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
    defer arena.deinit();
    const allocator = arena.allocator();

    for (items) |item| {
        const processed = try processItem(allocator, item);
        try outputResult(processed);
    }
    // All allocations freed when arena deinits
}

Logging

日志

  • Use
    std.log.scoped
    to create namespaced loggers; each module should define its own scoped logger for filtering.
  • Define a module-level
    const log
    at the top of the file; use it consistently throughout the module.
  • Use appropriate log levels:
    err
    for failures,
    warn
    for suspicious conditions,
    info
    for state changes,
    debug
    for tracing.
  • 使用
    std.log.scoped
    创建命名空间日志器;每个模块应定义自己的作用域日志器以便过滤。
  • 在文件顶部定义模块级别的
    const log
    ;在整个模块中一致地使用它。
  • 使用合适的日志级别:
    err
    表示失败,
    warn
    表示可疑情况,
    info
    表示状态变更,
    debug
    表示跟踪信息。

Examples

示例

Scoped logger for a module:
zig
const std = @import("std");
const log = std.log.scoped(.widgets);

pub fn createWidget(name: []const u8) !Widget {
    log.debug("creating widget: {s}", .{name});
    const widget = try allocateWidget(name);
    log.debug("created widget id={d}", .{widget.id});
    return widget;
}

pub fn deleteWidget(id: u32) void {
    log.info("deleting widget id={d}", .{id});
    // cleanup
}
Multiple scopes in a codebase:
zig
// In src/db.zig
const log = std.log.scoped(.db);

// In src/http.zig
const log = std.log.scoped(.http);

// In src/auth.zig
const log = std.log.scoped(.auth);
为模块定义作用域日志器:
zig
const std = @import("std");
const log = std.log.scoped(.widgets);

pub fn createWidget(name: []const u8) !Widget {
    log.debug("creating widget: {s}", .{name});
    const widget = try allocateWidget(name);
    log.debug("created widget id={d}", .{widget.id});
    return widget;
}

pub fn deleteWidget(id: u32) void {
    log.info("deleting widget id={d}", .{id});
    // cleanup
}
代码库中的多个作用域:
zig
// In src/db.zig
const log = std.log.scoped(.db);

// In src/http.zig
const log = std.log.scoped(.http);

// In src/auth.zig
const log = std.log.scoped(.auth);

Comptime Patterns

编译时模式

  • Use
    comptime
    parameters for generic functions; type information is available at compile time with zero runtime cost.
  • Prefer compile-time validation over runtime checks when possible. Catch errors during compilation rather than in production.
  • Use
    @compileError
    for invalid configurations that should fail the build.
  • 为泛型函数使用
    comptime
    参数;类型信息在编译时可用,且无运行时开销。
  • 尽可能优先使用编译时验证而非运行时检查。在编译阶段捕获错误而非在生产环境中。
  • 使用
    @compileError
    处理会导致构建失败的无效配置。

Examples

示例

Generic function with comptime type:
zig
fn max(comptime T: type, a: T, b: T) T {
    return if (a > b) a else b;
}
Compile-time validation:
zig
fn createBuffer(comptime size: usize) [size]u8 {
    if (size == 0) {
        @compileError("buffer size must be greater than 0");
    }
    return [_]u8{0} ** size;
}
带编译时类型参数的泛型函数:
zig
fn max(comptime T: type, a: T, b: T) T {
    return if (a > b) a else b;
}
编译时验证:
zig
fn createBuffer(comptime size: usize) [size]u8 {
    if (size == 0) {
        @compileError("buffer size must be greater than 0");
    }
    return [_]u8{0} ** size;
}

Avoiding anytype

避免使用anytype

  • Prefer
    comptime T: type
    over
    anytype
    ; explicit type parameters document expected constraints and produce clearer errors.
  • Use
    anytype
    only when the function genuinely accepts any type (like
    std.debug.print
    ) or for callbacks/closures.
  • When using
    anytype
    , add a doc comment describing the expected interface or constraints.
  • 优先使用
    comptime T: type
    而非
    anytype
    ;显式类型参数能明确预期约束并生成更清晰的错误信息。
  • 仅当函数确实能接受任意类型(如
    std.debug.print
    )或用于回调/闭包时才使用
    anytype
  • 使用
    anytype
    时,添加文档注释描述预期的接口或约束。

Examples

示例

Prefer explicit comptime type (good):
zig
fn sum(comptime T: type, items: []const T) T {
    var total: T = 0;
    for (items) |item| {
        total += item;
    }
    return total;
}
Avoid anytype when type is known (bad):
zig
// Unclear what types are valid; error messages will be confusing
fn sum(items: anytype) @TypeOf(items[0]) {
    // ...
}
Acceptable anytype for callbacks:
zig
/// Calls `callback` for each item. Callback must accept (T) and return void.
fn forEach(comptime T: type, items: []const T, callback: anytype) void {
    for (items) |item| {
        callback(item);
    }
}
Using @TypeOf when anytype is necessary:
zig
fn debugPrint(value: anytype) void {
    const T = @TypeOf(value);
    if (@typeInfo(T) == .Pointer) {
        std.debug.print("ptr: {*}\n", .{value});
    } else {
        std.debug.print("val: {}\n", .{value});
    }
}
优先使用显式编译时类型(推荐):
zig
fn sum(comptime T: type, items: []const T) T {
    var total: T = 0;
    for (items) |item| {
        total += item;
    }
    return total;
}
当类型已知时避免使用anytype(不推荐):
zig
// Unclear what types are valid; error messages will be confusing
fn sum(items: anytype) @TypeOf(items[0]) {
    // ...
}
回调场景下合理使用anytype:
zig
/// Calls `callback` for each item. Callback must accept (T) and return void.
fn forEach(comptime T: type, items: []const T, callback: anytype) void {
    for (items) |item| {
        callback(item);
    }
}
当必须使用anytype时结合@TypeOf:
zig
fn debugPrint(value: anytype) void {
    const T = @TypeOf(value);
    if (@typeInfo(T) == .Pointer) {
        std.debug.print("ptr: {*}\n", .{value});
    } else {
        std.debug.print("val: {}\n", .{value});
    }
}

Error Handling Patterns

错误处理模式

  • Define specific error sets for functions; avoid
    anyerror
    when possible. Specific errors document failure modes.
  • Use
    catch
    with a block for error recovery or logging; use
    catch unreachable
    only when errors are truly impossible.
  • Merge error sets with
    ||
    when combining operations that can fail in different ways.
  • 为函数定义特定的错误集;尽可能避免使用
    anyerror
    。特定错误集能明确失败模式。
  • 使用
    catch
    块进行错误恢复或日志记录;仅当错误确实不可能发生时才使用
    catch unreachable
  • 当组合可能以不同方式失败的操作时,使用
    ||
    合并错误集。

Examples

示例

Specific error set:
zig
const ConfigError = error{
    FileNotFound,
    ParseError,
    InvalidFormat,
};

fn loadConfig(path: []const u8) ConfigError!Config {
    // implementation
}
Error handling with catch block:
zig
const value = operation() catch |err| {
    std.log.err("operation failed: {}", .{err});
    return error.OperationFailed;
};
特定错误集:
zig
const ConfigError = error{
    FileNotFound,
    ParseError,
    InvalidFormat,
};

fn loadConfig(path: []const u8) ConfigError!Config {
    // implementation
}
使用catch块处理错误:
zig
const value = operation() catch |err| {
    std.log.err("operation failed: {}", .{err});
    return error.OperationFailed;
};

Configuration

配置管理

  • Load config from environment variables at startup; validate required values before use. Missing config should cause a clean exit with a descriptive message.
  • Define a Config struct as single source of truth; avoid
    std.posix.getenv
    scattered throughout code.
  • Use sensible defaults for development; require explicit values for production secrets.
  • 在启动时从环境变量加载配置;使用前验证必填值。缺失配置应导致程序干净退出并给出描述性消息。
  • 定义Config结构体作为单一可信数据源;避免在代码中分散使用
    std.posix.getenv
  • 为开发环境使用合理的默认值;生产环境的密钥需要显式配置。

Examples

示例

Typed config struct:
zig
const std = @import("std");

pub const Config = struct {
    port: u16,
    database_url: []const u8,
    api_key: []const u8,
    env: []const u8,
};

pub fn loadConfig() !Config {
    const db_url = std.posix.getenv("DATABASE_URL") orelse
        return error.MissingDatabaseUrl;
    const api_key = std.posix.getenv("API_KEY") orelse
        return error.MissingApiKey;
    const port_str = std.posix.getenv("PORT") orelse "3000";
    const port = std.fmt.parseInt(u16, port_str, 10) catch
        return error.InvalidPort;

    return .{
        .port = port,
        .database_url = db_url,
        .api_key = api_key,
        .env = std.posix.getenv("ENV") orelse "development",
    };
}
带类型的配置结构体:
zig
const std = @import("std");

pub const Config = struct {
    port: u16,
    database_url: []const u8,
    api_key: []const u8,
    env: []const u8,
};

pub fn loadConfig() !Config {
    const db_url = std.posix.getenv("DATABASE_URL") orelse
        return error.MissingDatabaseUrl;
    const api_key = std.posix.getenv("API_KEY") orelse
        return error.MissingApiKey;
    const port_str = std.posix.getenv("PORT") orelse "3000";
    const port = std.fmt.parseInt(u16, port_str, 10) catch
        return error.InvalidPort;

    return .{
        .port = port,
        .database_url = db_url,
        .api_key = api_key,
        .env = std.posix.getenv("ENV") orelse "development",
    };
}

Optionals

可选类型

  • Use
    orelse
    to provide default values for optionals; use
    .?
    only when null is a program error.
  • Prefer
    if (optional) |value|
    pattern for safe unwrapping with access to the value.
  • 使用
    orelse
    为可选类型提供默认值;仅当null是程序错误时才使用
    .?
  • 优先使用
    if (optional) |value|
    模式安全地解包并访问值。

Examples

示例

Safe optional handling:
zig
fn findWidget(id: u32) ?*Widget {
    // lookup implementation
}

fn processWidget(id: u32) !void {
    const widget = findWidget(id) orelse return error.WidgetNotFound;
    try widget.process();
}
Optional with if unwrapping:
zig
if (maybeValue) |value| {
    try processValue(value);
} else {
    std.log.warn("no value present", .{});
}
安全处理可选类型:
zig
fn findWidget(id: u32) ?*Widget {
    // lookup implementation
}

fn processWidget(id: u32) !void {
    const widget = findWidget(id) orelse return error.WidgetNotFound;
    try widget.process();
}
使用if解包可选类型:
zig
if (maybeValue) |value| {
    try processValue(value);
} else {
    std.log.warn("no value present", .{});
}

Advanced Topics

高级主题

Reference these guides for specialized patterns:
  • Building custom containers (queues, stacks, trees): See GENERICS.md
  • Interfacing with C libraries (raylib, SDL, curl, system APIs): See C-INTEROP.md
  • Debugging memory leaks (GPA, stack traces): See DEBUGGING.md
参考以下指南了解专业模式:
  • 构建自定义容器(队列、栈、树):参见 GENERICS.md
  • 与C库交互(raylib、SDL、curl、系统API):参见 C-INTEROP.md
  • 调试内存泄漏(GPA、栈跟踪):参见 DEBUGGING.md

Tooling

工具链

zigdoc - Documentation Lookup

zigdoc - 文档查询

CLI tool for browsing Zig std library and project dependency docs.
Install:
bash
git clone https://github.com/rockorager/zigdoc
cd zigdoc
zig build install -Doptimize=ReleaseFast --prefix $HOME/.local
Usage:
bash
zigdoc std.ArrayList       # std lib symbol
zigdoc std.mem.Allocator   # nested symbol
zigdoc vaxis.Window        # project dependency (if in build.zig)
zigdoc @init               # create AGENTS.md with API patterns
用于浏览Zig标准库和项目依赖文档的CLI工具。
安装:
bash
git clone https://github.com/rockorager/zigdoc
cd zigdoc
zig build install -Doptimize=ReleaseFast --prefix $HOME/.local
使用:
bash
zigdoc std.ArrayList       # std lib symbol
zigdoc std.mem.Allocator   # nested symbol
zigdoc vaxis.Window        # project dependency (if in build.zig)
zigdoc @init               # create AGENTS.md with API patterns

ziglint - Static Analysis

ziglint - 静态分析

Linter for Zig source code enforcing coding standards.
Install:
bash
git clone https://github.com/rockorager/ziglint
cd ziglint
zig build install -Doptimize=ReleaseFast --prefix $HOME/.local
Usage:
bash
ziglint                    # lint current directory (uses .ziglint.zon if present)
ziglint src build.zig      # lint specific paths
ziglint --ignore Z001      # suppress specific rule
Configuration (
.ziglint.zon
):
zig
.{
    .paths = .{ "src", "build.zig" },
    .rules = .{
        .Z001 = .{ .enabled = false },
        .Z024 = .{ .max_length = 80 },
    },
}
Inline suppression:
zig
fn MyBadName() void {} // ziglint-ignore: Z001
用于Zig源代码的代码检查工具,强制遵循编码规范。
安装:
bash
git clone https://github.com/rockorager/ziglint
cd ziglint
zig build install -Doptimize=ReleaseFast --prefix $HOME/.local
使用:
bash
ziglint                    # lint current directory (uses .ziglint.zon if present)
ziglint src build.zig      # lint specific paths
ziglint --ignore Z001      # suppress specific rule
配置(
.ziglint.zon
):
zig
.{
    .paths = .{ "src", "build.zig" },
    .rules = .{
        .Z001 = .{ .enabled = false },
        .Z024 = .{ .max_length = 80 },
    },
}
内联抑制:
zig
fn MyBadName() void {} // ziglint-ignore: Z001

References

参考资料