函数指针 #

一、函数指针基础 #

1.1 函数指针类型 #

使用 *const fn 定义函数指针类型:

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

const BinaryOp = *const fn (i32, i32) i32;

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

fn subtract(a: i32, b: i32) i32 {
    return a - b;
}

pub fn main() void {
    const op: BinaryOp = add;
    std.debug.print("add(10, 5) = {}\n", .{op(10, 5)});
    
    const op2: BinaryOp = subtract;
    std.debug.print("subtract(10, 5) = {}\n", .{op2(10, 5)});
}

1.2 函数指针作为参数 #

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

const CompareFn = *const fn (i32, i32) bool;

fn lessThan(a: i32, b: i32) bool {
    return a < b;
}

fn greaterThan(a: i32, b: i32) bool {
    return a > b;
}

fn findExtreme(arr: []const i32, compare: CompareFn) ?i32 {
    if (arr.len == 0) return null;
    
    var extreme = arr[0];
    for (arr[1..]) |item| {
        if (compare(item, extreme)) {
            extreme = item;
        }
    }
    return extreme;
}

pub fn main() void {
    const numbers = [_]i32{ 3, 7, 2, 9, 1, 5 };
    
    const min = findExtreme(&numbers, lessThan);
    const max = findExtreme(&numbers, greaterThan);
    
    std.debug.print("Min: {}, Max: {}\n", .{ min.?, max.? });
}

1.3 函数指针数组 #

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

const Operation = *const fn (i32, i32) i32;

fn add(a: i32, b: i32) i32 { return a + b; }
fn subtract(a: i32, b: i32) i32 { return a - b; }
fn multiply(a: i32, b: i32) i32 { return a * b; }
fn divide(a: i32, b: i32) i32 { return @divTrunc(a, b); }

pub fn main() void {
    const operations = [_]Operation{ add, subtract, multiply, divide };
    const names = [_][]const u8{ "add", "subtract", "multiply", "divide" };
    
    const a: i32 = 10;
    const b: i32 = 3;
    
    for (operations, names) |op, name| {
        std.debug.print("{s}({}, {}) = {}\n", .{ name, a, b, op(a, b) });
    }
}

二、回调函数 #

2.1 基本回调 #

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

const Callback = *const fn (i32) void;

fn processNumbers(arr: []const i32, callback: Callback) void {
    for (arr) |item| {
        callback(item);
    }
}

fn printNumber(n: i32) void {
    std.debug.print("{} ", .{n});
}

fn printSquare(n: i32) void {
    std.debug.print("{} ", .{n * n});
}

pub fn main() void {
    const numbers = [_]i32{ 1, 2, 3, 4, 5 };
    
    std.debug.print("Numbers: ", .{});
    processNumbers(&numbers, printNumber);
    std.debug.print("\n", .{});
    
    std.debug.print("Squares: ", .{});
    processNumbers(&numbers, printSquare);
    std.debug.print("\n", .{});
}

2.2 带上下文的回调 #

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

const Context = struct {
    sum: i32,
    count: usize,
};

const CallbackWithContext = *const fn (*Context, i32) void;

fn accumulate(ctx: *Context, value: i32) void {
    ctx.sum += value;
    ctx.count += 1;
}

fn processWithContext(arr: []const i32, ctx: *Context, callback: CallbackWithContext) void {
    for (arr) |item| {
        callback(ctx, item);
    }
}

pub fn main() void {
    const numbers = [_]i32{ 1, 2, 3, 4, 5 };
    var ctx = Context{ .sum = 0, .count = 0 };
    
    processWithContext(&numbers, &ctx, accumulate);
    
    std.debug.print("Sum: {}, Count: {}, Average: {d}\n", .{
        ctx.sum,
        ctx.count,
        @as(f64, @floatFromInt(ctx.sum)) / @as(f64, @floatFromInt(ctx.count)),
    });
}

2.3 事件处理 #

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

const EventHandler = *const fn ([]const u8) void;

const EventEmitter = struct {
    handlers: [10]?EventHandler,
    count: usize,
    
    fn init() EventEmitter {
        return .{
            .handlers = [_]?EventHandler{null} ** 10,
            .count = 0,
        };
    }
    
    fn on(self: *EventEmitter, handler: EventHandler) void {
        if (self.count < self.handlers.len) {
            self.handlers[self.count] = handler;
            self.count += 1;
        }
    }
    
    fn emit(self: EventEmitter, event: []const u8) void {
        for (self.handlers[0..self.count]) |handler| {
            if (handler) |h| {
                h(event);
            }
        }
    }
};

fn logHandler(event: []const u8) void {
    std.debug.print("Log: {s}\n", .{event});
}

fn alertHandler(event: []const u8) void {
    std.debug.print("Alert: {s}\n", .{event});
}

pub fn main() void {
    var emitter = EventEmitter.init();
    
    emitter.on(logHandler);
    emitter.on(alertHandler);
    
    emitter.emit("User logged in");
    emitter.emit("File uploaded");
}

三、高阶函数 #

3.1 map 函数 #

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

fn map(arr: []const i32, transform: *const fn (i32) i32, result: []i32) void {
    for (arr, result) |item, *r| {
        r.* = transform(item);
    }
}

fn double(x: i32) i32 { return x * 2; }
fn square(x: i32) i32 { return x * x; }
fn negate(x: i32) i32 { return -x; }

pub fn main() void {
    const numbers = [_]i32{ 1, 2, 3, 4, 5 };
    var result: [5]i32 = undefined;
    
    map(&numbers, double, &result);
    std.debug.print("Doubled: {any}\n", .{result});
    
    map(&numbers, square, &result);
    std.debug.print("Squared: {any}\n", .{result});
    
    map(&numbers, negate, &result);
    std.debug.print("Negated: {any}\n", .{result});
}

3.2 filter 函数 #

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

const Predicate = *const fn (i32) bool;

fn filter(arr: []const i32, predicate: Predicate, result: []i32) usize {
    var count: usize = 0;
    for (arr) |item| {
        if (predicate(item)) {
            result[count] = item;
            count += 1;
        }
    }
    return count;
}

fn isEven(x: i32) bool { return x % 2 == 0; }
fn isPositive(x: i32) bool { return x > 0; }
fn isGreaterThan3(x: i32) bool { return x > 3; }

pub fn main() void {
    const numbers = [_]i32{ -2, -1, 0, 1, 2, 3, 4, 5 };
    var result: [8]i32 = undefined;
    
    const even_count = filter(&numbers, isEven, &result);
    std.debug.print("Even: {any}\n", .{result[0..even_count]});
    
    const positive_count = filter(&numbers, isPositive, &result);
    std.debug.print("Positive: {any}\n", .{result[0..positive_count]});
    
    const gt3_count = filter(&numbers, isGreaterThan3, &result);
    std.debug.print("> 3: {any}\n", .{result[0..gt3_count]});
}

3.3 reduce 函数 #

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

const Reducer = *const fn (i32, i32) i32;

fn reduce(arr: []const i32, initial: i32, reducer: Reducer) i32 {
    var acc = initial;
    for (arr) |item| {
        acc = reducer(acc, item);
    }
    return acc;
}

fn add(a: i32, b: i32) i32 { return a + b; }
fn multiply(a: i32, b: i32) i32 { return a * b; }
fn max(a: i32, b: i32) i32 { return if (a > b) a else b; }
fn min(a: i32, b: i32) i32 { return if (a < b) a else b; }

pub fn main() void {
    const numbers = [_]i32{ 1, 2, 3, 4, 5 };
    
    std.debug.print("Sum: {}\n", .{reduce(&numbers, 0, add)});
    std.debug.print("Product: {}\n", .{reduce(&numbers, 1, multiply)});
    std.debug.print("Max: {}\n", .{reduce(&numbers, numbers[0], max)});
    std.debug.print("Min: {}\n", .{reduce(&numbers, numbers[0], min)});
}

四、实战示例 #

4.1 排序器 #

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

const CompareFn = *const fn (i32, i32) bool;

fn sort(arr: []i32, compare: CompareFn) void {
    var i: usize = arr.len;
    while (i > 1) : (i -= 1) {
        for (arr[0 .. i - 1], 0..) |*item, j| {
            if (compare(arr[j + 1], item.*)) {
                const temp = item.*;
                item.* = arr[j + 1];
                arr[j + 1] = temp;
            }
        }
    }
}

pub fn main() void {
    var numbers = [_]i32{ 5, 2, 8, 1, 9, 3, 7, 4, 6 };
    
    var ascending = numbers;
    sort(&ascending, struct {
        fn cmp(a: i32, b: i32) bool {
            return a < b;
        }
    }.cmp);
    std.debug.print("Ascending: {any}\n", .{ascending});
    
    var descending = numbers;
    sort(&descending, struct {
        fn cmp(a: i32, b: i32) bool {
            return a > b;
        }
    }.cmp);
    std.debug.print("Descending: {any}\n", .{descending});
}

4.2 命令模式 #

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

const Command = *const fn () void;

const CommandQueue = struct {
    commands: [10]?Command,
    count: usize,
    
    fn init() CommandQueue {
        return .{
            .commands = [_]?Command{null} ** 10,
            .count = 0,
        };
    }
    
    fn add(self: *CommandQueue, cmd: Command) void {
        if (self.count < self.commands.len) {
            self.commands[self.count] = cmd;
            self.count += 1;
        }
    }
    
    fn execute(self: CommandQueue) void {
        for (self.commands[0..self.count]) |cmd| {
            if (cmd) |c| {
                c();
            }
        }
    }
};

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

fn sayGoodbye() void {
    std.debug.print("Goodbye!\n", .{});
}

fn sayThanks() void {
    std.debug.print("Thanks!\n", .{});
}

pub fn main() void {
    var queue = CommandQueue.init();
    
    queue.add(sayHello);
    queue.add(sayThanks);
    queue.add(sayGoodbye);
    
    queue.execute();
}

五、总结 #

函数指针要点:

特性 说明
函数指针类型 *const fn(args) T
回调函数 函数指针作为参数
高阶函数 接受或返回函数
上下文 使用结构体传递状态

下一步,让我们学习结构体!

最后更新:2026-03-27