Zig 编译期
Zig 的编译期计算是其最强大的特性之一,它允许在编译时执行代码,生成高效的运行时代码。
编译期基础概念
comptime 关键字
comptime 关键字用于标记在编译时执行的代码:
zig
const std = @import("std");
pub fn main() void {
// 编译时常量
const compile_time_value = comptime 2 + 3;
std.debug.print("编译时计算: {}\n", .{compile_time_value});
// 编译时变量
comptime var counter = 0;
comptime {
counter += 1;
counter *= 2;
}
std.debug.print("编译时变量: {}\n", .{counter});
// 编译时循环
comptime var sum = 0;
comptime var i = 1;
comptime {
while (i <= 10) : (i += 1) {
sum += i;
}
}
std.debug.print("1到10的和 (编译时计算): {}\n", .{sum});
}编译时函数
函数可以在编译时执行:
zig
const std = @import("std");
// 编译时计算斐波那契数
fn fibonacci(n: u32) u32 {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 编译时计算阶乘
fn factorial(n: u32) u32 {
if (n <= 1) return 1;
return n * factorial(n - 1);
}
pub fn main() void {
// 在编译时计算
const fib_10 = comptime fibonacci(10);
const fact_5 = comptime factorial(5);
std.debug.print("斐波那契数列第10项: {}\n", .{fib_10});
std.debug.print("5的阶乘: {}\n", .{fact_5});
// 编译时生成数组
const fib_array = comptime blk: {
var array: [10]u32 = undefined;
for (array, 0..) |*item, i| {
item.* = fibonacci(@intCast(i));
}
break :blk array;
};
std.debug.print("斐波那契数组: ");
for (fib_array) |num| {
std.debug.print("{} ", .{num});
}
std.debug.print("\n");
}编译时类型操作
类型反射
zig
const std = @import("std");
const Point = struct {
x: f32,
y: f32,
z: f32,
};
const Color = enum {
Red,
Green,
Blue,
};
fn printTypeInfo(comptime T: type) void {
const type_info = @typeInfo(T);
std.debug.print("类型: {}\n", .{T});
std.debug.print("大小: {} 字节\n", .{@sizeOf(T)});
std.debug.print("对齐: {} 字节\n", .{@alignOf(T)});
switch (type_info) {
.Struct => |struct_info| {
std.debug.print("结构体字段数: {}\n", .{struct_info.fields.len});
for (struct_info.fields) |field| {
std.debug.print(" 字段: {s} (类型: {})\n", .{ field.name, field.type });
}
},
.Enum => |enum_info| {
std.debug.print("枚举值数: {}\n", .{enum_info.fields.len});
for (enum_info.fields) |field| {
std.debug.print(" 值: {s}\n", .{field.name});
}
},
.Int => |int_info| {
std.debug.print("整数位数: {}\n", .{int_info.bits});
std.debug.print("有符号: {}\n", .{int_info.signedness == .signed});
},
else => {},
}
std.debug.print("\n");
}
pub fn main() void {
comptime {
printTypeInfo(Point);
printTypeInfo(Color);
printTypeInfo(i32);
printTypeInfo(u64);
}
}泛型函数
zig
const std = @import("std");
// 泛型函数:适用于任何数字类型
fn add(comptime T: type, a: T, b: T) T {
return a + b;
}
// 泛型函数:计算数组最大值
fn max(comptime T: type, array: []const T) T {
if (array.len == 0) return 0;
var maximum = array[0];
for (array[1..]) |item| {
if (item > maximum) {
maximum = item;
}
}
return maximum;
}
// 泛型函数:交换两个值
fn swap(comptime T: type, a: *T, b: *T) void {
const temp = a.*;
a.* = b.*;
b.* = temp;
}
pub fn main() void {
// 使用泛型加法
std.debug.print("整数加法: {}\n", .{add(i32, 10, 20)});
std.debug.print("浮点加法: {d:.2}\n", .{add(f64, 3.14, 2.86)});
// 使用泛型最大值
const int_array = [_]i32{ 1, 5, 3, 9, 2 };
const float_array = [_]f32{ 1.1, 5.5, 3.3, 9.9, 2.2 };
std.debug.print("整数数组最大值: {}\n", .{max(i32, &int_array)});
std.debug.print("浮点数组最大值: {d:.1}\n", .{max(f32, &float_array)});
// 使用泛型交换
var x: i32 = 100;
var y: i32 = 200;
std.debug.print("交换前: x={}, y={}\n", .{ x, y });
swap(i32, &x, &y);
std.debug.print("交换后: x={}, y={}\n", .{ x, y });
}编译时字符串处理
字符串操作
zig
const std = @import("std");
// 编译时字符串连接
fn compileTimeConcat(comptime str1: []const u8, comptime str2: []const u8) []const u8 {
return str1 ++ str2;
}
// 编译时字符串重复
fn compileTimeRepeat(comptime str: []const u8, comptime count: usize) []const u8 {
comptime var result: []const u8 = "";
comptime var i = 0;
comptime {
while (i < count) : (i += 1) {
result = result ++ str;
}
}
return result;
}
// 编译时生成格式化字符串
fn compileTimeFormat(comptime fmt: []const u8, args: anytype) []const u8 {
return comptime std.fmt.comptimePrint(fmt, args);
}
pub fn main() void {
// 编译时字符串操作
const greeting = comptime compileTimeConcat("Hello, ", "World!");
const repeated = comptime compileTimeRepeat("Zig ", 3);
const formatted = comptime compileTimeFormat("Version: {}.{}.{}", .{ 1, 0, 0 });
std.debug.print("连接字符串: {s}\n", .{greeting});
std.debug.print("重复字符串: {s}\n", .{repeated});
std.debug.print("格式化字符串: {s}\n", .{formatted});
// 编译时生成标识符
const field_name = comptime compileTimeConcat("field_", "name");
std.debug.print("生成的标识符: {s}\n", .{field_name});
}编译时代码生成
生成结构体
zig
const std = @import("std");
// 编译时生成结构体
fn generateStruct(comptime fields: []const struct { name: []const u8, type: type }) type {
comptime var struct_fields: [fields.len]std.builtin.Type.StructField = undefined;
comptime {
for (fields, 0..) |field, i| {
struct_fields[i] = std.builtin.Type.StructField{
.name = field.name,
.type = field.type,
.default_value = null,
.is_comptime = false,
.alignment = @alignOf(field.type),
};
}
}
return @Type(std.builtin.Type{
.Struct = std.builtin.Type.Struct{
.layout = .Auto,
.fields = &struct_fields,
.decls = &[_]std.builtin.Type.Declaration{},
.is_tuple = false,
},
});
}
pub fn main() void {
// 定义字段
const fields = [_]struct { name: []const u8, type: type }{
.{ .name = "id", .type = u32 },
.{ .name = "name", .type = []const u8 },
.{ .name = "score", .type = f64 },
};
// 生成结构体类型
const Student = comptime generateStruct(&fields);
// 使用生成的结构体
const student = Student{
.id = 12345,
.name = "张三",
.score = 95.5,
};
std.debug.print("学生信息:\n");
std.debug.print(" ID: {}\n", .{student.id});
std.debug.print(" 姓名: {s}\n", .{student.name});
std.debug.print(" 分数: {d:.1}\n", .{student.score});
}生成函数
zig
const std = @import("std");
// 编译时生成getter函数
fn generateGetter(comptime T: type, comptime field_name: []const u8) fn (*const T) @TypeOf(@field(@as(T, undefined), field_name)) {
return struct {
fn get(self: *const T) @TypeOf(@field(@as(T, undefined), field_name)) {
return @field(self, field_name);
}
}.get;
}
// 编译时生成setter函数
fn generateSetter(comptime T: type, comptime field_name: []const u8) fn (*T, @TypeOf(@field(@as(T, undefined), field_name))) void {
return struct {
fn set(self: *T, value: @TypeOf(@field(@as(T, undefined), field_name))) void {
@field(self, field_name) = value;
}
}.set;
}
const Person = struct {
name: []const u8,
age: u32,
// 编译时生成的getter和setter
const getName = comptime generateGetter(Person, "name");
const getAge = comptime generateGetter(Person, "age");
const setName = comptime generateSetter(Person, "name");
const setAge = comptime generateSetter(Person, "age");
};
pub fn main() void {
var person = Person{
.name = "李四",
.age = 25,
};
// 使用生成的getter
std.debug.print("姓名: {s}\n", .{person.getName()});
std.debug.print("年龄: {}\n", .{person.getAge()});
// 使用生成的setter
person.setName("王五");
person.setAge(30);
std.debug.print("更新后:\n");
std.debug.print("姓名: {s}\n", .{person.getName()});
std.debug.print("年龄: {}\n", .{person.getAge()});
}编译时条件编译
平台相关代码
zig
const std = @import("std");
const builtin = @import("builtin");
// 编译时平台检测
const is_windows = comptime builtin.os.tag == .windows;
const is_linux = comptime builtin.os.tag == .linux;
const is_macos = comptime builtin.os.tag == .macos;
// 平台相关的路径分隔符
const path_separator = comptime if (is_windows) "\\" else "/";
// 平台相关的换行符
const line_ending = comptime if (is_windows) "\r\n" else "\n";
// 编译时选择实现
fn getPlatformName() []const u8 {
return comptime if (is_windows)
"Windows"
else if (is_linux)
"Linux"
else if (is_macos)
"macOS"
else
"Unknown";
}
pub fn main() void {
std.debug.print("当前平台: {s}\n", .{getPlatformName()});
std.debug.print("路径分隔符: {s}\n", .{path_separator});
std.debug.print("换行符长度: {}\n", .{line_ending.len});
// 编译时特性检测
const has_vector_support = comptime builtin.cpu.arch.endian() == .Little;
std.debug.print("小端序支持: {}\n", .{has_vector_support});
// 编译时优化级别
const optimization_level = comptime switch (builtin.mode) {
.Debug => "调试",
.ReleaseSafe => "安全发布",
.ReleaseFast => "快速发布",
.ReleaseSmall => "小体积发布",
};
std.debug.print("优化级别: {s}\n", .{optimization_level});
}特性开关
zig
const std = @import("std");
// 编译时特性开关
const ENABLE_LOGGING = true;
const ENABLE_PROFILING = false;
const DEBUG_MODE = @import("builtin").mode == .Debug;
// 条件编译的日志函数
fn log(comptime fmt: []const u8, args: anytype) void {
if (comptime ENABLE_LOGGING) {
std.debug.print("[LOG] " ++ fmt ++ "\n", args);
}
}
// 条件编译的性能分析
fn profile(comptime name: []const u8, func: anytype) @TypeOf(func()) {
if (comptime ENABLE_PROFILING) {
std.debug.print("[PROFILE] 开始: {s}\n", .{name});
const start_time = std.time.nanoTimestamp();
const result = func();
const end_time = std.time.nanoTimestamp();
const duration = end_time - start_time;
std.debug.print("[PROFILE] 结束: {s}, 耗时: {}ns\n", .{ name, duration });
return result;
} else {
return func();
}
}
// 调试断言
fn debugAssert(condition: bool, comptime message: []const u8) void {
if (comptime DEBUG_MODE) {
if (!condition) {
std.debug.panic("断言失败: " ++ message, .{});
}
}
}
pub fn main() void {
log("程序开始执行", .{});
const result = profile("计算操作", struct {
fn compute() i32 {
var sum: i32 = 0;
for (0..1000) |i| {
sum += @intCast(i);
}
return sum;
}
}.compute);
debugAssert(result > 0, "计算结果应该大于0");
log("计算结果: {}", .{result});
log("程序执行完成", .{});
}编译时内存分配
编译时数组生成
zig
const std = @import("std");
// 编译时生成查找表
fn generateLookupTable(comptime size: usize) [size]u32 {
comptime var table: [size]u32 = undefined;
comptime {
for (table, 0..) |*item, i| {
item.* = @intCast(i * i); // 平方表
}
}
return table;
}
// 编译时生成素数表
fn generatePrimeTable(comptime limit: usize) []const u32 {
comptime var primes: [limit]u32 = undefined;
comptime var count: usize = 0;
comptime {
var num: u32 = 2;
while (num < limit and count < limit) : (num += 1) {
var is_prime = true;
var i: u32 = 2;
while (i * i <= num) : (i += 1) {
if (num % i == 0) {
is_prime = false;
break;
}
}
if (is_prime) {
primes[count] = num;
count += 1;
}
}
}
return primes[0..count];
}
pub fn main() void {
// 使用编译时生成的查找表
const square_table = comptime generateLookupTable(10);
std.debug.print("平方表 (0-9):\n");
for (square_table, 0..) |square, i| {
std.debug.print("{}² = {}\n", .{ i, square });
}
// 使用编译时生成的素数表
const primes = comptime generatePrimeTable(100);
std.debug.print("\n前{}个素数:\n", .{primes.len});
for (primes, 0..) |prime, i| {
std.debug.print("{}: {}\n", .{ i + 1, prime });
if (i >= 9) break; // 只显示前10个
}
}编译时错误处理
编译时验证
zig
const std = @import("std");
// 编译时验证函数参数
fn validateAtCompileTime(comptime value: i32) void {
if (value < 0) {
@compileError("值不能为负数");
}
if (value > 100) {
@compileError("值不能大于100");
}
}
// 编译时验证类型
fn requireNumericType(comptime T: type) void {
const type_info = @typeInfo(T);
switch (type_info) {
.Int, .Float => {},
else => @compileError("类型必须是数字类型"),
}
}
// 编译时验证数组大小
fn requireMinArraySize(comptime T: type, comptime min_size: usize) void {
const type_info = @typeInfo(T);
switch (type_info) {
.Array => |array_info| {
if (array_info.len < min_size) {
@compileError(std.fmt.comptimePrint("数组大小必须至少为{}", .{min_size}));
}
},
else => @compileError("类型必须是数组"),
}
}
// 使用编译时验证的函数
fn processValue(comptime value: i32) i32 {
comptime validateAtCompileTime(value);
return value * 2;
}
fn processArray(comptime T: type, array: T) void {
comptime requireMinArraySize(T, 3);
comptime requireNumericType(@TypeOf(array[0]));
std.debug.print("处理数组,大小: {}\n", .{array.len});
for (array[0..3]) |item| {
std.debug.print(" {}\n", .{item});
}
}
pub fn main() void {
// 这些会在编译时验证
const result1 = comptime processValue(50); // OK
// const result2 = comptime processValue(-10); // 编译错误
// const result3 = comptime processValue(150); // 编译错误
std.debug.print("处理结果: {}\n", .{result1});
// 数组验证
const valid_array = [_]i32{ 1, 2, 3, 4, 5 };
// const invalid_array = [_]i32{ 1, 2 }; // 编译错误:数组太小
processArray(@TypeOf(valid_array), valid_array);
}编译时性能优化
预计算优化
zig
const std = @import("std");
// 编译时预计算三角函数表
const SIN_TABLE_SIZE = 360;
const sin_table = comptime blk: {
var table: [SIN_TABLE_SIZE]f64 = undefined;
for (table, 0..) |*item, i| {
const angle = @as(f64, @floatFromInt(i)) * std.math.pi / 180.0;
item.* = @sin(angle);
}
break :blk table;
};
// 快速正弦查找
fn fastSin(degrees: u32) f64 {
return sin_table[degrees % SIN_TABLE_SIZE];
}
// 编译时预计算CRC表
const CRC_TABLE = comptime blk: {
var table: [256]u32 = undefined;
for (table, 0..) |*item, i| {
var crc: u32 = @intCast(i);
for (0..8) |_| {
if (crc & 1 != 0) {
crc = (crc >> 1) ^ 0xEDB88320;
} else {
crc >>= 1;
}
}
item.* = crc;
}
break :blk table;
};
// 快速CRC计算
fn fastCrc32(data: []const u8) u32 {
var crc: u32 = 0xFFFFFFFF;
for (data) |byte| {
const table_index = @as(u8, @truncate(crc)) ^ byte;
crc = (crc >> 8) ^ CRC_TABLE[table_index];
}
return crc ^ 0xFFFFFFFF;
}
pub fn main() void {
// 使用预计算的正弦表
std.debug.print("正弦值:\n");
for ([_]u32{ 0, 30, 45, 60, 90 }) |angle| {
std.debug.print("sin({}°) = {d:.6}\n", .{ angle, fastSin(angle) });
}
// 使用预计算的CRC表
const test_data = "Hello, Zig!";
const crc = fastCrc32(test_data);
std.debug.print("\nCRC32(\"{s}\") = 0x{X}\n", .{ test_data, crc });
}总结
本章详细介绍了 Zig 的编译期特性:
- ✅
comptime关键字和编译时执行 - ✅ 编译时类型操作和反射
- ✅ 泛型函数和类型参数
- ✅ 编译时字符串处理
- ✅ 编译时代码生成
- ✅ 条件编译和特性开关
- ✅ 编译时内存分配
- ✅ 编译时错误处理和验证
- ✅ 编译时性能优化
Zig 的编译期系统是其最独特和强大的特性,它让开发者能够在编译时完成大量工作,生成高效的运行时代码。在下一章中,我们将学习 Zig 的数组与切片。