变量与常量 #
一、变量声明 #
1.1 var 关键字 #
使用 var 声明可变变量:
zig
const std = @import("std");
pub fn main() void {
var count: i32 = 0;
count = 10;
count += 5;
std.debug.print("count = {}\n", .{count});
}
1.2 const 关键字 #
使用 const 声明常量:
zig
const std = @import("std");
pub fn main() void {
const pi: f64 = 3.14159;
const name = "Zig";
std.debug.print("pi = {d}\n", .{pi});
std.debug.print("name = {s}\n", .{name});
}
1.3 类型推断 #
Zig 可以自动推断类型:
zig
const std = @import("std");
pub fn main() void {
const inferred_int = 42; // 推断为 comptime_int
const inferred_float = 3.14; // 推断为 comptime_float
const inferred_string = "hello"; // 推断为 *const [5:0]u8
std.debug.print("{}\n", .{@TypeOf(inferred_int)});
std.debug.print("{}\n", .{@TypeOf(inferred_float)});
std.debug.print("{}\n", .{@TypeOf(inferred_string)});
}
二、const vs var #
2.1 常量(const) #
zig
const std = @import("std");
pub fn main() void {
const x: i32 = 10;
// x = 20; // 编译错误:不能修改常量
// 但如果 const 是指针,可以修改指向的值
var value: i32 = 10;
const ptr: *i32 = &value;
ptr.* = 20; // 这是允许的
std.debug.print("value = {}\n", .{value});
}
2.2 变量(var) #
zig
const std = @import("std");
pub fn main() void {
var x: i32 = 10;
x = 20; // 允许修改
// var 必须被使用,否则会警告
var y: i32 = 30;
std.debug.print("x = {}, y = {}\n", .{ x, y });
}
2.3 选择原则 #
| 场景 | 使用 |
|---|---|
| 值不会改变 | const |
| 值需要改变 | var |
| 编译时已知 | const 或 comptime |
| 运行时确定 | var 或 const |
三、const 的特殊行为 #
3.1 const 指针 #
zig
const std = @import("std");
pub fn main() void {
var value: i32 = 10;
// const 指针,可以修改指向的值
const ptr: *i32 = &value;
ptr.* = 20;
// const 常量指针,不能修改指针本身
const ptr2: *const i32 = &value;
// ptr2.* = 30; // 错误:不能修改 const 指向的值
std.debug.print("value = {}\n", .{value});
}
3.2 const 切片 #
zig
const std = @import("std");
pub fn main() void {
var arr = [_]i32{ 1, 2, 3, 4, 5 };
// const 切片,可以修改元素
const slice: []i32 = arr[0..];
slice[0] = 100;
// const 切片指向 const 数据
const const_slice: []const i32 = arr[0..];
// const_slice[0] = 200; // 错误
std.debug.print("arr[0] = {}\n", .{arr[0]});
}
四、comptime #
4.1 编译时计算 #
comptime 关键字强制在编译时执行:
zig
const std = @import("std");
pub fn main() void {
comptime {
const x = 10;
const y = 20;
std.debug.print("Compile time: {}\n", .{x + y});
}
}
4.2 comptime 参数 #
函数参数可以是编译时已知的:
zig
const std = @import("std");
fn fibonacci(comptime n: u32) u32 {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
pub fn main() void {
const result = comptime fibonacci(10);
std.debug.print("fibonacci(10) = {}\n", .{result});
}
4.3 comptime 类型 #
zig
const std = @import("std");
fn printType(comptime T: type) void {
std.debug.print("Type: {}\n", .{T});
}
pub fn main() void {
printType(i32);
printType(f64);
printType([]const u8);
}
4.4 comptime 变量 #
zig
const std = @import("std");
pub fn main() void {
comptime var i: usize = 0;
inline while (i < 5) : (i += 1) {
std.debug.print("{}\n", .{i});
}
}
五、变量初始化 #
5.1 显式初始化 #
zig
const std = @import("std");
pub fn main() void {
var x: i32 = 10;
var y: f64 = 3.14;
var name: []const u8 = "Zig";
std.debug.print("x = {}, y = {d}, name = {s}\n", .{ x, y, name });
}
5.2 未定义值 #
使用 undefined 表示未初始化:
zig
const std = @import("std");
pub fn main() void {
var x: i32 = undefined;
x = 10; // 必须在使用前赋值
std.debug.print("x = {}\n", .{x});
}
5.3 默认值 #
zig
const std = @import("std");
const Point = struct {
x: i32 = 0,
y: i32 = 0,
};
pub fn main() void {
const p1 = Point{};
const p2 = Point{ .x = 10 };
const p3 = Point{ .x = 10, .y = 20 };
std.debug.print("p1: ({}, {})\n", .{ p1.x, p1.y });
std.debug.print("p2: ({}, {})\n", .{ p2.x, p2.y });
std.debug.print("p3: ({}, {})\n", .{ p3.x, p3.y });
}
六、作用域 #
6.1 块作用域 #
zig
const std = @import("std");
pub fn main() void {
const x = 10;
{
const x = 20; // 遮蔽外层 x
std.debug.print("Inner x = {}\n", .{x});
}
std.debug.print("Outer x = {}\n", .{x});
}
6.2 文件作用域 #
zig
const std = @import("std");
const file_constant = 100; // 文件级别常量
pub fn main() void {
std.debug.print("file_constant = {}\n", .{file_constant});
}
6.3 全局变量 #
zig
const std = @import("std");
var global_counter: i32 = 0;
fn increment() void {
global_counter += 1;
}
pub fn main() void {
increment();
increment();
increment();
std.debug.print("global_counter = {}\n", .{global_counter});
}
七、类型转换 #
7.1 显式转换 #
zig
const std = @import("std");
pub fn main() void {
const a: i32 = 100;
const b: f32 = @floatFromInt(a);
const c: u8 = @intCast(a);
std.debug.print("a = {}, b = {d}, c = {}\n", .{ a, b, c });
}
7.2 常用转换函数 #
| 函数 | 说明 |
|---|---|
@intCast |
整数类型转换 |
@floatCast |
浮点类型转换 |
@floatFromInt |
整数转浮点 |
@intFromFloat |
浮点转整数 |
@intFromBool |
布尔转整数 |
@intFromPtr |
指针转整数 |
@ptrFromInt |
整数转指针 |
@truncate |
截断整数 |
@as |
通用类型转换 |
7.3 @as 用法 #
zig
const std = @import("std");
pub fn main() void {
const x = @as(i32, 10);
const y = @as(f64, 3.14);
const z = @as(u8, 255);
std.debug.print("x = {}, y = {d}, z = {}\n", .{ x, y, z });
}
八、常量表达式 #
8.1 编译时常量 #
zig
const std = @import("std");
const SIZE: usize = 100;
const BUFFER_SIZE = SIZE * 2;
pub fn main() void {
var buffer: [BUFFER_SIZE]u8 = undefined;
std.debug.print("Buffer size = {}\n", .{buffer.len});
}
8.2 运行时常量 #
zig
const std = @import("std");
pub fn main() void {
const input = try std.io.getStdIn().reader().readByte();
const doubled = input * 2; // 运行时计算
std.debug.print("doubled = {}\n", .{doubled});
}
九、最佳实践 #
9.1 优先使用 const #
zig
// 好
const max_size = 100;
const default_name = "unknown";
// 避免
var max_size = 100; // 不需要修改
var default_name = "unknown";
9.2 避免变量遮蔽 #
zig
// 不推荐
const x = 10;
const x = 20; // 遮蔽
// 推荐
const x = 10;
const y = 20;
9.3 使用有意义的名称 #
zig
// 好
const max_connections = 100;
const user_name = "Alice";
var item_count: usize = 0;
// 不好
const mc = 100;
const n = "Alice";
var cnt: usize = 0;
十、总结 #
变量与常量要点:
| 概念 | 说明 |
|---|---|
| const | 不可变绑定 |
| var | 可变变量 |
| comptime | 编译时执行 |
| undefined | 未定义值 |
| 类型推断 | 自动推断类型 |
下一步,让我们学习 Zig 的基本数据类型!
最后更新:2026-03-27