Zig 0.11.0中std::function等价物及函数引用映射实现方法
在Zig 0.11.0中实现i32到函数引用的映射
Zig没有直接对应C++ std::function的内置类型,但可以根据函数签名是否统一,用两种方案实现需求:
1. 统一函数签名场景(最简单)
如果所有要关联的函数都有完全一致的签名,直接用函数指针作为哈希表的值类型即可,这是最高效的方案。
示例代码:
const std = @import("std"); const allocator = std.heap.page_allocator; // 定义统一的函数签名 const HandlerFn = fn(value: i32) void; pub fn main() !void { // 初始化HashMap:key为i32,value为HandlerFn类型的函数指针 var map = std.HashMap(i32, HandlerFn).init(allocator); defer map.deinit(); // 定义几个符合签名的函数 fn printDouble(n: i32) void { std.debug.print("Double: {}\n", .{n * 2}); } fn printSquare(n: i32) void { std.debug.print("Square: {}\n", .{n * n}); } // 向映射中插入键值对 try map.put(1, printDouble); try map.put(2, printSquare); // 根据key获取函数并调用 if (map.get(1)) |fn_ptr| { fn_ptr(5); // 输出:Double: 10 } if (map.get(2)) |fn_ptr| { fn_ptr(5); // 输出:Square: 25 } }
2. 不同函数签名场景(模拟std::function的多态)
如果需要关联的函数签名不同(比如参数数量、类型或返回值不同),可以通过类型擦除封装一个通用的可调用结构体,模拟std::function的行为。
示例代码:
const std = @import("std"); const allocator = std.heap.page_allocator; // 封装通用可调用对象:通过类型擦除支持不同签名的函数/闭包 const Callable = struct { ctx: anyopaque, // 这里的call函数可根据实际需求调整参数和返回值,示例统一为接收i32参数、无返回值 call: fn(ctx: anyopaque, arg: i32) void, // 辅助函数:将普通函数转换为Callable pub fn fromFn(comptime Fn: type, fn_ptr: Fn) Callable { // 编译期校验函数签名 comptime std.debug.assert(std.meta.FnTypeOf(Fn) == fn(i32) void); return .{ .ctx = @ptrCast(anyopaque, fn_ptr), .call = struct { fn call(ctx: anyopaque, arg: i32) void { const f = @ptrCast(Fn, ctx); f(arg); } }.call, }; } // 辅助函数:将闭包转换为Callable(闭包需分配在堆上) pub fn fromClosure(comptime Closure: type, closure: *Closure) Callable { return .{ .ctx = closure, .call = struct { fn call(ctx: anyopaque, arg: i32) void { const c = @ptrCast(*Closure, @alignCast(@alignOf(Closure), ctx)); c.call(arg); } }.call, }; } }; pub fn main() !void { var map = std.HashMap(i32, Callable).init(allocator); defer map.deinit(); // 插入普通函数 fn printTriple(n: i32) void { std.debug.print("Triple: {}\n", .{n * 3}); } try map.put(3, Callable.fromFn(@TypeOf(printTriple), printTriple)); // 插入闭包(堆分配后需手动销毁) var closure = try allocator.create(struct { factor: i32, fn call(self: *@This(), n: i32) void { std.debug.print("Multiplied by {}: {}\n", .{self.factor, n * self.factor}); } }); defer allocator.destroy(closure); closure.factor = 4; try map.put(4, Callable.fromClosure(@TypeOf(closure), closure)); // 调用映射中的函数 if (map.get(3)) |callable| { callable.call(callable.ctx, 5); // 输出:Triple: 15 } if (map.get(4)) |callable| { callable.call(callable.ctx, 5); // 输出:Multiplied by 4: 20 } }
注意事项
- 闭包在Zig中是带上下文的结构体,需要手动管理内存(示例中用堆分配,记得销毁)。
- 类型擦除会带来少量性能开销,若不需要多态性,优先选择第一种方案。
- Zig 0.11.0的
std.HashMap需要手动调用deinit释放资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者user16028444
相关产品推荐
相关产品推荐

