函数基础 #

一、函数定义 #

1.1 基本函数 #

zig
const std = @import("std");

fn greet() void {
    std.debug.print("Hello, Zig!\n", .{});
}

pub fn main() void {
    greet();
}

1.2 带参数的函数 #

zig
const std = @import("std");

fn add(a: i32, b: i32) i32 {
    return a + b;
}

pub fn main() void {
    const result = add(10, 20);
    std.debug.print("Result: {}\n", .{result});
}

1.3 多返回值 #

Zig 不支持多返回值,但可以返回元组或结构体:

zig
const std = @import("std");

fn divideAndRemainder(a: i32, b: i32) struct { quotient: i32, remainder: i32 } {
    return .{
        .quotient = @divTrunc(a, b),
        .remainder = @rem(a, b),
    };
}

pub fn main() void {
    const result = divideAndRemainder(17, 5);
    std.debug.print("17 / 5 = {} remainder {}\n", .{ result.quotient, result.remainder });
}

1.4 忽略返回值 #

zig
const std = @import("std");

fn getValue() i32 {
    return 42;
}

pub fn main() void {
    _ = getValue();  // 忽略返回值
    std.debug.print("Ignored return value\n", .{});
}

二、参数 #

2.1 值传递 #

默认情况下,参数是值传递:

zig
const std = @import("std");

fn double(value: i32) i32 {
    var v = value;
    v *= 2;
    return v;
}

pub fn main() void {
    const x: i32 = 10;
    const result = double(x);
    std.debug.print("x = {}, result = {}\n", .{ x, result });
}

2.2 指针传递 #

使用指针可以修改原始值:

zig
const std = @import("std");

fn doubleInPlace(value: *i32) void {
    value.* *= 2;
}

pub fn main() void {
    var x: i32 = 10;
    doubleInPlace(&x);
    std.debug.print("x = {}\n", .{x});
}

2.3 切片参数 #

zig
const std = @import("std");

fn sum(numbers: []const i32) i32 {
    var total: i32 = 0;
    for (numbers) |n| {
        total += n;
    }
    return total;
}

pub fn main() void {
    const arr = [_]i32{ 1, 2, 3, 4, 5 };
    const result = sum(&arr);
    std.debug.print("Sum: {}\n", .{result});
}

2.4 可选参数 #

zig
const std = @import("std");

fn greet(name: ?[]const u8) void {
    const actual_name = name orelse "Anonymous";
    std.debug.print("Hello, {s}!\n", .{actual_name});
}

pub fn main() void {
    greet(null);
    greet("Alice");
}

2.5 默认值 #

Zig 不支持函数参数默认值,但可以使用结构体:

zig
const std = @import("std");

const Options = struct {
    verbose: bool = false,
    timeout: u32 = 30,
    retries: u32 = 3,
};

fn connect(host: []const u8, options: Options) void {
    std.debug.print("Connecting to {s}\n", .{host});
    std.debug.print("  verbose: {}\n", .{options.verbose});
    std.debug.print("  timeout: {}\n", .{options.timeout});
    std.debug.print("  retries: {}\n", .{options.retries});
}

pub fn main() void {
    connect("example.com", .{});
    connect("example.com", .{ .verbose = true });
    connect("example.com", .{ .timeout = 60, .retries = 5 });
}

三、返回值 #

3.1 基本返回值 #

zig
const std = @import("std");

fn square(x: i32) i32 {
    return x * x;
}

pub fn main() void {
    std.debug.print("Square of 5: {}\n", .{square(5)});
}

3.2 错误返回 #

zig
const std = @import("std");

fn divide(a: i32, b: i32) !i32 {
    if (b == 0) return error.DivisionByZero;
    return @divTrunc(a, b);
}

pub fn main() void {
    const result = divide(10, 2) catch |err| {
        std.debug.print("Error: {}\n", .{err});
        return;
    };
    std.debug.print("Result: {}\n", .{result});
}

3.3 可选返回 #

zig
const std = @import("std");

fn findIndex(arr: []const i32, target: i32) ?usize {
    for (arr, 0..) |value, i| {
        if (value == target) return i;
    }
    return null;
}

pub fn main() void {
    const arr = [_]i32{ 10, 20, 30, 40, 50 };
    if (findIndex(&arr, 30)) |i| {
        std.debug.print("Found at index: {}\n", .{i});
    } else {
        std.debug.print("Not found\n", .{});
    }
}

3.4 隐式返回 #

函数末尾的值会隐式返回:

zig
const std = @import("std");

fn max(a: i32, b: i32) i32 {
    if (a > b) return a;
    b
}

pub fn main() void {
    std.debug.print("Max: {}\n", .{max(10, 20)});
}

四、defer #

4.1 基本 defer #

defer 在函数返回前执行:

zig
const std = @import("std");

fn process() void {
    std.debug.print("Start\n", .{});
    defer std.debug.print("Cleanup\n", .{});
    std.debug.print("Processing\n", .{});
}

pub fn main() void {
    process();
}

4.2 defer 执行顺序 #

多个 defer 按 LIFO 顺序执行:

zig
const std = @import("std");

fn example() void {
    defer std.debug.print("First defer\n", .{});
    defer std.debug.print("Second defer\n", .{});
    defer std.debug.print("Third defer\n", .{});
    std.debug.print("Body\n", .{});
}

pub fn main() void {
    example();
}

4.3 defer 用于资源清理 #

zig
const std = @import("std");

fn readFile(path: []const u8) !void {
    const file = try std.fs.cwd().openFile(path, .{});
    defer file.close();
    
    var buffer: [100]u8 = undefined;
    const bytes_read = try file.readAll(&buffer);
    std.debug.print("Read {} bytes\n", .{bytes_read});
}

4.4 defer 与作用域 #

zig
const std = @import("std");

pub fn main() void {
    std.debug.print("Start\n", .{});
    
    {
        defer std.debug.print("Block defer\n", .{});
        std.debug.print("Block body\n", .{});
    }
    
    std.debug.print("After block\n", .{});
}

五、errdefer #

5.1 基本 errdefer #

errdefer 只在函数返回错误时执行:

zig
const std = @import("std");

fn mightFail(success: bool) !void {
    std.debug.print("Start\n", .{});
    errdefer std.debug.print("Error cleanup\n", .{});
    
    if (!success) {
        return error.Failure;
    }
    
    std.debug.print("Success\n", .{});
}

pub fn main() void {
    std.debug.print("--- Success case ---\n", .{});
    mightFail(true) catch {};
    
    std.debug.print("\n--- Error case ---\n", .{});
    mightFail(false) catch {};
}

5.2 资源清理模式 #

zig
const std = @import("std");

fn allocateAndProcess(allocator: std.mem.Allocator, size: usize) ![]u8 {
    const buffer = try allocator.alloc(u8, size);
    errdefer allocator.free(buffer);
    
    for (buffer, 0..) |*b, i| {
        b.* = @intCast(i % 256);
    }
    
    return buffer;
}

pub fn main() void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    const buffer = allocateAndProcess(allocator, 10) catch |err| {
        std.debug.print("Error: {}\n", .{err});
        return;
    };
    defer allocator.free(buffer);
    
    std.debug.print("Buffer: {any}\n", .{buffer});
}

六、函数可见性 #

6.1 pub 函数 #

pub 使函数对外可见:

zig
const std = @import("std");

pub fn publicFunction() void {
    std.debug.print("Public function\n", .{});
}

fn privateFunction() void {
    std.debug.print("Private function\n", .{});
}

pub fn main() void {
    publicFunction();
    privateFunction();
}

6.2 文件作用域 #

zig
// utils.zig
pub fn utility() void {
    std.debug.print("Utility function\n", .{});
}

fn internal() void {
    std.debug.print("Internal function\n", .{});

const std = @import("std");
zig
// main.zig
const std = @import("std");
const utils = @import("utils.zig");

pub fn main() void {
    utils.utility();
    // utils.internal();  // 错误:不可见
}

七、实战示例 #

7.1 字符串处理函数 #

zig
const std = @import("std");

fn trimWhitespace(str: []const u8) []const u8 {
    var start: usize = 0;
    var end: usize = str.len;
    
    while (start < end and (str[start] == ' ' or str[start] == '\t')) {
        start += 1;
    }
    
    while (end > start and (str[end - 1] == ' ' or str[end - 1] == '\t')) {
        end -= 1;
    }
    
    return str[start..end];
}

pub fn main() void {
    const str = "   hello world   ";
    const trimmed = trimWhitespace(str);
    std.debug.print("Original: '{s}'\n", .{str});
    std.debug.print("Trimmed: '{s}'\n", .{trimmed});
}

7.2 文件处理函数 #

zig
const std = @import("std");

fn readAllFile(path: []const u8, allocator: std.mem.Allocator) ![]u8 {
    const file = try std.fs.cwd().openFile(path, .{});
    defer file.close();
    
    const stat = try file.stat();
    const content = try allocator.alloc(u8, stat.size);
    errdefer allocator.free(content);
    
    _ = try file.readAll(content);
    return content;
}

pub fn main() void {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    defer _ = gpa.deinit();
    const allocator = gpa.allocator();
    
    const content = readAllFile("test.txt", allocator) catch |err| {
        std.debug.print("Error: {}\n", .{err});
        return;
    };
    defer allocator.free(content);
    
    std.debug.print("Content: {s}\n", .{content});
}

八、最佳实践 #

8.1 函数命名 #

zig
// 好:动词开头
fn calculateTotal() i32 {}
fn validateInput() bool {}
fn sendEmail() !void {}

// 避免:名词
fn total() i32 {}
fn inputValidation() bool {}

8.2 单一职责 #

zig
// 好:每个函数做一件事
fn validateEmail(email: []const u8) bool {
    return std.mem.indexOf(u8, email, "@") != null;
}

fn sendEmail(to: []const u8, subject: []const u8, body: []const u8) !void {
    // 发送邮件
}

// 避免:函数做太多事
fn validateAndSendEmail(email: []const u8, subject: []const u8, body: []const u8) !void {
    if (std.mem.indexOf(u8, email, "@") == null) return error.InvalidEmail;
    // 发送邮件
}

8.3 使用 defer 清理资源 #

zig
// 好
fn processFile(path: []const u8) !void {
    const file = try std.fs.cwd().openFile(path, .{});
    defer file.close();
    
    // 处理文件
}

// 避免:忘记关闭
fn processFileBad(path: []const u8) !void {
    const file = try std.fs.cwd().openFile(path, .{});
    // 处理文件
    // 忘记关闭文件
}

九、总结 #

函数基础要点:

特性 说明
fn 函数定义关键字
pub 公开可见性
参数 值传递为主
返回值 支持多种类型
defer 延迟执行
errdefer 错误时延迟执行

下一步,让我们学习泛型函数!

最后更新:2026-03-27