Zig 变量教程
1. 变量基础
Section titled “1. 变量基础”1.1 什么是变量?
Section titled “1.1 什么是变量?”变量是内存存储单元,用于存储数据。
1.2 变量声明原则
Section titled “1.2 变量声明原则”优先使用 const 而非 var:
- 便于人类和计算机阅读代码
- 创造更多优化机会
// 推荐:使用 constconst PI: f64 = 3.14159;
// 必要时才用 varvar counter: i32 = 0;counter += 1;2. 变量标识符规则
Section titled “2. 变量标识符规则”2.1 命名规则
Section titled “2.1 命名规则”- 必须以字母或下划线开头
- 后面可跟任意数量的字母数字字符或下划线
- 不能与关键字冲突
- 不允许遮蔽外部作用域的标识符
// 合法标识符const normalName = 42;const _private = 100;const MAX_SIZE = 1024;
// 非法标识符(会导致编译错误)// const 123name = 10; // 数字开头不允许2.2 特殊命名需求
Section titled “2.2 特殊命名需求”如果需要特殊名称(如链接外部库),使用 @"" 语法:
const @"identifier with spaces in it" = 0xff;const @"1SmallStep4Man" = 112358;
// 用于链接 C 库pub extern "c" fn @"error"() void;pub extern "c" fn @"fstat$INODE64"(fd: c.fd_t, buf: *c.Stat) c_int;
// 枚举中的特殊名称const Color = enum { red, @"really red", // 带空格的枚举值};const color: Color = .@"really red";3. 变量作用域类型
Section titled “3. 变量作用域类型”3.1 容器级变量(Container Level Variables)
Section titled “3.1 容器级变量(Container Level Variables)”特性:
- 具有静态生命周期
- 顺序无关(Zig 会智能分析依赖关系)
- 延迟分析
- 初始化值隐式是编译期已知的
// 注意:y 使用了 x,但 x 在 y 之后声明// Zig 能正确分析这种依赖关系var y: i32 = add(10, x);const x: i32 = add(12, 34);
fn add(a: i32, b: i32) i32 { return a + b;}
// 测试:x = 12 + 34 = 46, y = 10 + 46 = 56// x 是 const,编译期已知// y 是 var,运行时已知在结构体、联合、枚举或不透明类型中:
const S = struct { var counter: i32 = 0; // 容器级变量};
fn increment() i32 { S.counter += 1; return S.counter;}3.2 静态局部变量(Static Local Variables)
Section titled “3.2 静态局部变量(Static Local Variables)”在函数内部使用容器来创建静态局部变量:
fn makeCounter() fn() i32 { const Counter = struct { var value: i32 = 0; // 静态局部变量 };
return fn() i32 { Counter.value += 1; return Counter.value; };}
// 使用示例const counter = makeCounter();counter(); // 返回 1counter(); // 返回 2counter(); // 返回 33.3 线程局部变量(Thread Local Variables)
Section titled “3.3 线程局部变量(Thread Local Variables)”使用 threadlocal 关键字为每个线程创建独立的变量实例:
threadlocal var threadId: i32 = 0;
test "线程局部存储" { // 每个线程都有自己独立的 threadId 副本 const thread1 = try std.Thread.spawn(.{}, worker, .{}); const thread2 = try std.Thread.spawn(.{}, worker, .{});
thread1.join(); thread2.join();}
fn worker() void { threadId = std.Thread.getCurrentId(); std.debug.print("Thread ID: {}\n", .{threadId});}重要限制:
- 线程局部变量不能是
const - 在单线程构建中,线程局部变量被当作普通容器级变量处理
3.4 局部变量(Local Variables)
Section titled “3.4 局部变量(Local Variables)”出现在函数、编译期块和 @cImport 块中:
fn example() void { // 普通局部变量 var x: i32 = 10; x += 5;
// const 局部变量 const y: i32 = 20; // y = 30; // 错误:const 变量不能修改
// 如果 const 变量的初始值是编译期已知的,那么变量也是编译期已知的 const MAX_BUFFER_SIZE = 1024; // 编译期已知}4. 编译期变量
Section titled “4. 编译期变量”使用 comptime 关键字声明编译期变量:
test "编译期变量" { var runtimeVar: i32 = 1; comptime var compileTimeVar: i32 = 1; // 编译期变量
runtimeVar += 1; // 运行时执行 compileTimeVar += 1; // 编译时执行
// 编译期变量的值在编译时已知 if (compileTimeVar != 2) { @compileError("compileTimeVar 应该是 2"); }
// 编译期表达式中的所有变量隐式是编译期变量 comptime { var a: i32 = 5; // 隐式 comptime a *= 2; // 编译时计算 std.debug.assert(a == 10); }}编译期变量的特点:
- 所有加载和存储操作在语义分析期间发生
- 可用于编译时计算和条件编译
5. 外部和导出变量
Section titled “5. 外部和导出变量”5.1 链接外部变量
Section titled “5.1 链接外部变量”使用 extern 或 @extern 链接其他对象导出的变量:
// 链接外部 C 变量extern "c" var errno: c_int;
// 或使用 @externconst externalVar = @extern(*i32, .{ .name = "global_counter" });5.2 导出变量
Section titled “5.2 导出变量”使用 export 或 @export 使变量在链接时对其他对象可用:
// 导出变量给其他模块使用export var exported_counter: i32 = 0;
// 或使用 @exportvar internal_counter: i32 = 0;@export(internal_counter, .{ .name = "exported_name" });重要要求: 导出/导入的变量类型必须是 C ABI 兼容的。
6. 最佳实践总结
Section titled “6. 最佳实践总结”- 默认使用
const,只在需要修改时使用var - 遵循命名规范,使用
@""语法处理特殊情况 - 理解作用域:区分容器级、局部、线程局部变量
- 善用编译期变量:用于编译时计算和优化
- 注意线程安全:使用
threadlocal处理线程特定数据 - 正确使用外部链接:确保类型兼容性
7. 实用示例
Section titled “7. 实用示例”const std = @import("std");
// 容器级配置常量(编译期已知)const Config = struct { const MAX_USERS = 1000; const TIMEOUT_MS = 5000;
// 运行时配置(可能从文件加载) var debug_mode: bool = false;};
// 线程局部存储threadlocal var current_user_id: ?u32 = null;
// 静态局部计数器fn makeUniqueId() u64 { const State = struct { var next_id: u64 = 1; // 静态局部变量 };
const id = State.next_id; State.next_id += 1; return id;}
pub fn main() void { // 局部变量 const user_count = 42; var connection_active = true;
// 编译期计算 comptime { const buffer_size = Config.MAX_USERS * @sizeOf(User); std.debug.print("Buffer size needed: {}\n", .{buffer_size}); }
// 使用线程局部存储 current_user_id = 123;
std.debug.print("Unique IDs: {}, {}, {}\n", .{ makeUniqueId(), makeUniqueId(), makeUniqueId(), });}通过掌握这些变量类型和用法,你可以编写出更安全、更高效、更易于维护的 Zig 代码。