Zig编译期函数中字面量的生命周期探究
函数内字面量的生命周期
以下代码中,函数返回的引用是无效指针吗?
fn hello() *const u8 { return &'A'; }
不是,因为'A'字面量拥有静态生命周期。那如下函数呢?
fn world(c: u8) []const u8 { return &.{ c }; }
依旧不是,因为该字面量数组同样拥有静态生命周期,但多次调用会出现异常行为:
const a = world('a'); const b = world('b'); print("{s} {s}\n", .{a, b});
输出:
b b
之前的值('a')被覆盖了,因为所有world()调用引用的是同一个字面量。
编译期函数(comptime函数)
如果将world()改为编译期函数会发生什么?
fn world(comptime c: u8) []const u8 { return &.{ c }; }
显然,每次调用都会创建一个独立的静态字面量:
const a = world('a'); const b = world('b'); print("{s} {s}\n", .{a, b});
输出:
a b
构建字面量树的辅助函数
现在来看一个实际场景中的同类问题。
我定义了Regex类型表示正则表达式:
const Regex = union(enum) { literal: u8, sequence: []const Regex, repeat: *const Regex, choice: []const Regex, };
但直接编写字面量正则表达式十分繁琐:
const regex: Regex = .{ .sequence = &.{ .{ .literal = 'h' }, .{ .choice = &.{ ... } } } };
为简化字面量正则表达式的编写,我们可以使用辅助函数:
// 使正则表达式可选(即`?`操作符) fn opt(comptime self: Regex) Regex { // 在自身与空序列间选择 return .{ .choice = &.{ self, .{ .sequence = &.{} } } }; }
我们还可以实现一个将字符串字面量转换为正则表达式(字面量序列)的函数。
只要函数是编译期函数,这似乎就能正常工作,但我需要完全确认其正确性,请纠正我对字面量生命周期的理解偏差。
Zig的comptimePrint
Zig标准库中恰好有这样的函数:std.fmt.comptimePrint,它创建一个局部变量并返回其指针。
pub inline fn comptimePrint(comptime fmt: []const u8, args: anytype) *const [count(fmt, args):0]u8 { comptime { var buf: [count(fmt, args):0]u8 = undefined; _ = bufPrint(&buf, fmt, args) catch unreachable; buf[buf.len] = 0; return &buf; } }
请问inline和comptime { ... }的作用是什么?为什么它们是必需的?如果去掉会发生什么?返回的缓冲区是否拥有静态生命周期?
内容的提问来源于stack exchange,提问作者uben
相关产品推荐
相关产品推荐

