Zig 基本语法
Zig 是一种现代系统编程语言,语法简洁、明确,旨在提供高性能、安全性和易维护性。它的语法受到 C 和 Rust 的启发,但去除了复杂特性(如宏、操作符重载),并通过编译时检查增强安全性。以下是对 Zig 基本语法的中文讲解,涵盖变量、数据类型、控制流、函数、错误处理等核心内容,结合示例代码,力求简洁清晰,基于 Zig 0.14.1(截至 2025 年 5 月的稳定版)。
1. 基本概念
- 静态类型:Zig 是强类型语言,变量类型在编译时确定,支持类型推断。
- 无隐藏控制流:所有操作显式,避免隐式行为。
- 编译时执行:通过
comptime
支持编译时计算,优化性能。 - 无垃圾回收:手动管理内存,使用分配器(allocator)。
2. 变量与常量
Zig 使用 var
声明变量,const
声明常量,comptime
用于编译时常量。
示例
const std = @import("std");
pub fn main() !void {
// 常量(不可变)
const a: i32 = 10;
// 变量(可变)
var b: i32 = 20;
b += a;
// 类型推断
const c = 30; // 自动推断为 i32
var d = b + c; // 自动推断为 i32
// 编译时常量
comptime var result = a + b;
const stdout = std.io.getStdOut().writer();
try stdout.print("结果: {}\n", .{result}); // 输出:结果: 30
}
说明:
const
:值不可修改,编译时确定。var
:值可修改,需显式指定类型或通过初始值推断。- 类型后缀(如
i32
):明确变量类型。 comptime
:确保表达式在编译时计算。
3. 基本数据类型
Zig 提供丰富的内置类型,类型名称简洁。
基本类型
- 整数:
- 有符号:
i8
,i16
,i32
,i64
,i128
。 - 无符号:
u8
,u16
,u32
,u64
,u128
。 - 任意大小:
isize
,usize
(依赖平台)。 - 浮点数:
f32
,f64
。 - 布尔值:
bool
(true
或false
)。 - 空类型:
void
。 - 可选类型:
?T
(表示可能为null
)。
var optional: ?i32 = null;
- 错误联合:
!T
(表示可能返回错误)。 - 指针:
- 单元素:
*T
。 - 多元素:
[*]T
,[]T
(切片,需指定长度或运行时确定)。 - 数组:
[N]T
(固定长度)。
var arr: [3]i32 = [_]i32{1, 2, 3};
示例
const std = @import("std");
pub fn main() !void {
var num: u32 = 42;
var optional: ?f32 = 3.14;
var arr: [2]u8 = [_]u8{10, 20};
const stdout = std.io.getStdOut().writer();
try stdout.print("无符号: {}, 可选: {}, 数组: {}\n", .{num, optional orelse 0.0, arr[0]});
}
输出:
无符号: 42, 可选: 3.14, 数组: 10
说明:
orelse
:处理可选类型的默认值。[_]T{...}
:数组初始化,_
自动推断长度。
4. 控制流
Zig 支持常见的控制结构,语法简洁。
条件语句
if
:支持条件分支,可处理可选类型和错误。
var x: ?i32 = 10;
if (x) |value| {
std.debug.print("值: {}\n", .{value}); // 输出:值: 10
} else {
std.debug.print("为空\n", .{});
}
- 比较运算符:
==
,!=
,<
,>
,<=
,>=
。 - 逻辑运算符:
and
,or
,!
。
循环
for
:迭代数组、切片等。
const arr = [_]u8{1, 2, 3};
for (arr) |item| {
std.debug.print("项: {}\n", .{item});
}
while
:支持条件循环。
var i: u32 = 0;
while (i < 3) : (i += 1) {
std.debug.print("计数: {}\n", .{i});
}
输出:
项: 1
项: 2
项: 3
计数: 0
计数: 1
计数: 2
说明:
for
捕获值使用|value|
。while
的: (i += 1)
是继续表达式,简化循环更新。
Switch
类似 C 的 switch
,但更灵活,支持范围和枚举。
var x: u8 = 2;
switch (x) {
1 => std.debug.print("一\n", .{}),
2, 3 => std.debug.print("二或三\n", .{}),
else => std.debug.print("其他\n", .{}),
}
输出:
二或三
5. 函数
Zig 的函数定义使用 fn
,支持返回值、错误处理和编译时参数。
基本函数
fn add(a: i32, b: i32) i32 {
return a + b;
}
pub fn main() !void {
const result = add(5, 3);
std.debug.print("加法: {}\n", .{result}); // 输出:加法: 8
}
错误处理
使用 !T
表示可能返回错误。
const MyError = error{InvalidInput};
fn divide(a: f32, b: f32) MyError!f32 {
if (b == 0) return MyError.InvalidInput;
return a / b;
}
pub fn main() !void {
const result = divide(10.0, 2.0) catch |err| {
std.debug.print("错误: {}\n", .{err});
return;
};
std.debug.print("除法: {}\n", .{result}); // 输出:除法: 5.0
}
说明:
try
:尝试调用可能出错的函数,失败时返回错误。catch
:捕获错误并处理。
6. 内存管理
Zig 没有垃圾回收,依赖分配器管理内存。
示例
const std = @import("std");
pub fn main() !void {
const allocator = std.heap.page_allocator;
var list = try std.ArrayList(u32).init(allocator);
defer list.deinit(); // 确保释放内存
try list.append(42);
std.debug.print("列表: {}\n", .{list.items[0]}); // 输出:列表: 42
}
说明:
std.ArrayList
:动态数组,需分配器。defer
:在函数退出时执行清理。try
:处理内存分配错误。
7. 结构体与枚举
- 结构体:定义自定义数据类型。
const Point = struct {
x: f32,
y: f32,
fn distance(self: Point) f32 {
return @sqrt(self.x * self.x + self.y * self.y);
}
};
pub fn main() !void {
const p = Point{ .x = 3.0, .y = 4.0 };
std.debug.print("距离: {}\n", .{p.distance()}); // 输出:距离: 5.0
}
- 枚举:定义有限值集合。
const Color = enum { Red, Green, Blue };
pub fn main() !void {
const c = Color.Green;
std.debug.print("颜色: {}\n", .{c}); // 输出:颜色: Green
}
8. 注意事项
- 类型安全:
- 显式类型声明或推断,避免类型错误。
- 可选类型(
?T
)和错误联合(!T
)防止未定义行为。 - 编译时优化:
- 使用
comptime
减少运行时开销。 - 避免复杂编译时逻辑,保持代码清晰。
- 错误处理:
- 所有可能失败的操作需显式处理(
try
、catch
)。 - 定义清晰的错误集(如
error{...}
)。 - 调试:
- 使用
std.debug.print
输出调试信息。 - 编译时启用调试:
zig build-exe -g
。 - 性能:
- Zig 编译为本地机器码,性能接近 C。
- 手动内存管理需小心,避免泄漏。
9. 综合示例
以下是一个综合示例,展示变量、控制流、函数和错误处理:
const std = @import("std");
const MyError = error{OutOfRange};
fn checkAge(age: u8) MyError!u8 {
if (age < 18 or age > 100) return MyError.OutOfRange;
return age;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
const ages = [_]u8{15, 25, 120};
for (ages) |age| {
const result = checkAge(age) catch |err| {
try stdout.print("年龄 {} 错误: {}\n", .{age, err});
continue;
};
try stdout.print("有效年龄: {}\n", .{result});
}
}
运行:
zig run example.zig
输出:
年龄 15 错误: OutOfRange
有效年龄: 25
年龄 120 错误: OutOfRange
10. 总结
Zig 的语法简洁而强大,结合静态类型、编译时执行和显式错误处理,提供高性能和安全性。核心特性包括:
const
和var
声明变量。- 丰富的基本类型(
i32
,u8
,?T
,[]T
)。 - 控制流(
if
,for
,while
,switch
)清晰直观。 - 函数支持错误处理(
!T
)和编译时优化。 - 手动内存管理通过分配器实现。
Zig 适合系统编程和性能敏感场景,学习曲线适中,推荐通过 Ziglings(https://ziglings.org/)和官方文档(https://ziglang.org/documentation/)深入学习。
如果你需要更复杂的语法示例(如并发、C 互操作)或有其他问题,请告诉我!