diff --git a/course/.vitepress/theme/config.ts b/course/.vitepress/theme/config.ts index b1e7a486..49d49919 100644 --- a/course/.vitepress/theme/config.ts +++ b/course/.vitepress/theme/config.ts @@ -1,3 +1,3 @@ -const version: string = "0.14.0"; +const version: string = "0.15.1"; export { version }; diff --git a/course/update/0.15.1-description.md b/course/update/0.15.1-description.md new file mode 100644 index 00000000..8f9a3835 --- /dev/null +++ b/course/update/0.15.1-description.md @@ -0,0 +1,244 @@ +--- +outline: deep +comments: false +showVersion: false +--- + +# `0.15.1` + +2025/1/20,`0.15.1` 发布,自上一个版本来历时 5 个月,共有 162 位贡献者参与,进行了 647 次提交! + +Zig 官方团队直接从 `0.14.0` 跨越到了 `0.15.1`。在默认选择 Zig 的 x86 后端后,调试编译速度提高了 **5** 倍;正在开发的 aarch64 后端也紧随其后。同时,随着 `Writergate` 事件以及一系列语言变更和标准库的调整,**大量** API 有破坏性更改;这预示着 async/await 即将重生;也是语言稳定化的最后关头。 + +## 编译器重大改进 + +### x86 后端性能突破 + +**调试模式**的编译速度提高了 **5** 倍;这是本次更新最显著的性能改进。x86 后端现在是**调试模式**的默认选择,为缩短开发周期提供了强有力的支持。 + +### aarch64 后端开发进展 + +aarch64 后端的开发也在稳步推进,持续优化 ARM 平台支持,为多架构开发提供更好的体验。 + +### 增量编译功能增强 + +增量编译功能得到了进一步优化,现在支持: + +- 与文件系统监视结合使用 +- 仅检查编译错误模式 +- 更快的重建速度 + +### 多线程代码生成 + +编译器现已支持多线程代码生成,能够充分利用多核 CPU 的性能优势。 + +## 语言特性重大调整 + +### 移除 `usingnamespace` 关键字 + +这是一个**破坏性变更**,`usingnamespace` 关键字被完全移除。所有使用 `usingnamespace` 的代码都需要重写,建议采用显式导入方式替代,以提高代码可读性和可维护性。 + +### 移除异步关键字 + +`async` 和 `await` 关键字已被移除,当前异步编程模型也随之取消,为未来新的异步方案做准备。这预示着 Zig 协程 的重生。 + +### 增强对非穷尽枚举的 `switch` 支持 + +新增对非穷尽枚举使用 `switch` 语句的支持,提高了枚举处理的灵活性,能够更好地处理未知枚举值,增强代码的健壮性。 + +### 扩展布尔向量运算符支持 + +布尔向量现在支持更多运算符,包括逻辑运算和比较运算。 + +### 内联汇编:类型化的破坏描述符 + +内联汇编现在支持类型化的 `clobber` 列表,提供了更好的类型安全保证。 + +### 指针转换能力增强 + +`@ptrCast` 现在允许从单项指针转换为切片,提供了更大的灵活性。 + +### 调整 `undefined` 运算规则 + +对 `undefined` 值的算术运算规则有所调整,任何与 `undefined` 的运算结果都将返回 `undefined`。 + +### 加强有损转换检测 + +对于可能导致精度损失的整数到浮点数转换,编译器会视为错误。 + +## 标准库重大变更 + +### Writergate:I/O 接口完全重构 + +这是本次更新中**最重大的破坏性更改**,被社区称为 "Writergate": + +- `std.io.Reader` 和 `std.io.Writer` 接口被完全重新设计 +- 新接口采用非泛型设计 +- 缓冲区位于接口之上 +- 旨在提高性能并减少不必要的拷贝 +- **需要大量代码重写** + +### 格式化系统调整 + +格式化系统进行了重要调整: + +- 调用自定义 `format` 方法需要使用 `{f}` 格式说明符 +- `format` 方法签名简化,移除了格式字符串和选项参数 +- 格式化打印不再处理 Unicode +- 新增了更多格式化说明符 + +### `ArrayList` 非托管化 + +容器类型的重要变更: + +- `std.ArrayList` 现在默认采用非托管方式 +- 开发者需要显式提供分配器 +- 与其他非托管容器保持一致 +- 提供更好的内存管理控制 + +### 链表去泛型化 + +链表类型进行了重构,去除了泛型化设计。 + +### HTTP 客户端和服务器 + +标准库新增了 HTTP 支持,提供内置的 HTTP 客户端和服务器功能。 + +### TLS 客户端 + +新增内置 TLS 支持,可以建立安全的 TLS 连接。 + +### 环形缓冲区 + +新增了环形缓冲区类型,提供高效的循环缓冲区实现。 + +### 移除 BoundedArray + +`BoundedArray` 被移除,建议使用 `ArrayList` 或固定大小数组替代。 + +## 构建系统改进 + +### 移除隐式根模块 + +构建系统移除了对隐式根模块的支持,现在需要在构建脚本中明确指定模块;这提高了构建配置的清晰度和准确性。 + +### macOS 文件系统监视 + +在 macOS 上新增了文件系统监视功能: + +- 能够在文件更改时自动触发重建 +- 支持 `--watch` 和 `--debounce` 选项 +- 显著提高开发效率 + +### Web 界面和时间报告 + +构建系统现在支持 Web 界面和详细的时间报告功能。 + +### 模糊测试器 + +Zig 0.15.1 集成了一个内置的模糊测试器: + +- 支持进程内模糊测试 +- 提供 Web UI 界面 +- 支持实时代码覆盖率显示 +- 可以快速发现代码中的潜在问题 + +## 工具链更新 + +### LLVM 20 + +升级到 LLVM 20,带来了: + +- 更好的优化支持 +- 新的目标架构支持 +- 改进的调试信息生成 +- 更好的 C++ 交互性 + +### FreeBSD 和 NetBSD libc 支持 + +在交叉编译时新增了对动态链接的 FreeBSD 和 NetBSD libc 的支持。 + +### glibc 2.42 + +升级到 glibc 2.42,并支持静态链接本机 glibc。 + +### MinGW-w64 更新 + +MinGW-w64 工具链得到了更新,进一步改进了对 Windows 的交叉编译支持。 + +### zig libc 和 zig cc 增强 + +`zig libc` 和 `zig cc` 命令的功能得到了增强: + +- 更好的 GCC 兼容性 +- 支持更多编译选项 +- 更清晰的错误报告 + +## 版本跳跃说明 + +Zig 官方团队选择直接从 `0.14.0` 跳跃到 `0.15.1`,这一决策反映了: + +- 本次更新包含的重大变更数量之多 +- 对编译器性能的重要改进 +- 标准库接口的重大重构 +- 为未来版本奠定更坚实的基础 + +## 升级挑战与机遇 + +### 主要挑战 + +1. **Writergate**:I/O 接口的完全重构需要重写大量相关代码 +2. **移除 `usingnamespace`**:需要调整导入方式 +3. **异步代码调整**:需要移除 async/await 使用 +4. **ArrayList 变更**:需要调整容器使用方式 + +### 主要机遇 + +1. **编译速度提升**:5 倍的调试编译速度改进 +2. **更清晰的代码**:移除隐式行为,提高代码可读性 +3. **更好的性能**:新的 I/O 接口设计更高效 +4. **开发效率**:文件系统监视功能和模糊测试器 + +## 社区影响 + +这次更新对 Zig 社区产生了重要影响: + +- **学习曲线**:新用户需要适应新的接口设计 +- **迁移工作**:现有项目需要进行大量调整 +- **性能收益**:编译速度的显著提升改善开发体验 +- **生态系统**:库作者需要更新以适配新接口 + +## 技术债务清理 + +本次更新体现了 Zig 团队对技术债务的积极清理: + +- 移除了有争议的 `usingnamespace` 特性 +- 重构了性能不佳的 I/O 接口 +- 统一了容器类型的设计理念 +- 为未来的语言演进奠定坚实基础 + +## 未来展望 + +`0.15.1` 为 Zig 的未来发展奠定了重要基础: + +- **编译性能**:为大型项目开发提供更好支持 +- **接口设计**:更一致、更高效的标准库 +- **开发体验**:更快的编译和更好的工具支持 +- **语言稳定性**:移除不稳定特性,为 1.0 做准备 + +## 路线图 + +### I/O 作为接口 + +I/O 系统将继续作为接口进行发展和完善,为未来的异步编程模型做准备。 + +## 建议 + +对于 Zig 开发者: + +1. **谨慎升级**:在测试环境中充分验证 +2. **分步迁移**:逐步调整代码以适配新接口 +3. **充分利用性能优势**:积极采用有关编译速度的改进 +4. **关注社区动态**:参与社区讨论,分享迁移经验和最佳实践 + +`0.15.1` 是 Zig 发展历程中的一个重要里程碑,虽然带来了较多的破坏性变更,但为语言的长期发展和性能提升奠定了坚实的基础。这标志着语言稳定化的最后阶段,为 1.0 版本的正式发布做好了充分准备。 diff --git a/course/update/upgrade-0.15.1.md b/course/update/upgrade-0.15.1.md new file mode 100644 index 00000000..b7d979e7 --- /dev/null +++ b/course/update/upgrade-0.15.1.md @@ -0,0 +1,1143 @@ +--- +outline: deep +showVersion: false +--- + +本篇文档将介绍如何从 `0.14.0` 版本升级到 `0.15.1`。 +本次发布凝聚了 162 位贡献者 在 5 个月内 647 次提交的成果。在将 Zig 的 **x86 后端** 设为 **调试模式** 的默认选项后,其编译速度提升了 5 倍;同时,正在积极开发的 **aarch64 后端** 也取得了显著进展。此外,**Writergate** 以及一系列语言变更和标准库调整,带来了大量的 **API 破坏性更改**。 + +## 语言变更 + +### 移除 `usingnamespace` + +`usingnamespace` 关键字已被移除。以下是常见用例的替代方案: + +#### 用例:条件包含 + +```zig +// 旧代码 +const builtin = @import("builtin"); +const os_impl = switch (builtin.os.tag) { + .linux => @import("os/linux.zig"), + .windows => @import("os/windows.zig"), + else => @compileError("Unsupported OS"), +}; +usingnamespace os_impl; +``` + +⬇️ + +```zig +// 新代码 +const builtin = @import("builtin"); +const os_impl = switch (builtin.os.tag) { + .linux => @import("os/linux.zig"), + .windows => @import("os/windows.zig"), + else => @compileError("Unsupported OS"), +}; + +// 显式导出所需函数 +pub const open = os_impl.open; +pub const close = os_impl.close; +pub const read = os_impl.read; +pub const write = os_impl.write; +``` + +#### 用例:实现切换 + +```zig +// 旧代码 +const MyStruct = struct { + data: u32, + + usingnamespace if (builtin.mode == .Debug) + @import("debug_impl.zig") + else + @import("release_impl.zig"); +}; +``` + +⬇️ + +```zig +// 新代码 +const Impl = if (builtin.mode == .Debug) + @import("debug_impl.zig") +else + @import("release_impl.zig"); + +const MyStruct = struct { + data: u32, + + pub fn doSomething(self: *MyStruct) void { + return Impl.doSomething(self); + } + + // 显式实现所有需要的方法 +}; +``` + +#### 用例:混入 + +```zig +// 旧代码 +fn LoggingMixin(comptime T: type) type { + return struct { + pub fn log(self: *T, message: []const u8) void { + std.log.info("{s}: {s}", .{ @typeName(T), message }); + } + }; +} + +const MyStruct = struct { + data: u32, + usingnamespace LoggingMixin(@This()); +}; +``` + +⬇️ + +```zig +// 新代码 +fn LoggingMixin(comptime T: type) type { + return struct { + pub fn log(self: *T, message: []const u8) void { + std.log.info("{s}: {s}", .{ @typeName(T), message }); + } + }; +} + +const MyStruct = struct { + data: u32, + + const Mixin = LoggingMixin(@This()); + + pub fn log(self: *MyStruct, message: []const u8) void { + Mixin.log(self, message); + } +}; +``` + +### 移除 `async` 和 `await` 关键字 + +`async` 和 `await` 关键字已被移除。这为未来引入新的异步编程方案做准备。 + +```zig +// 旧代码 - 将不再工作 +fn asyncFunction() async void { + // 异步代码 +} + +fn caller() void { + const frame = async asyncFunction(); + await frame; +} +``` + +目前需要使用其他方式处理并发,等待未来版本中新的异步编程支持。 + +### 对非穷尽枚举的 `switch` 支持 + +现在可以对非穷尽枚举使用 `switch` 语句: + +```zig +const MyEnum = enum(u8) { + foo = 1, + bar = 2, + _, +}; + +fn handleEnum(value: MyEnum) void { + switch (value) { + .foo => std.debug.print("foo\n", .{}), + .bar => std.debug.print("bar\n", .{}), + else => std.debug.print("unknown\n", .{}), + } +} +``` + +### 允许对布尔向量使用更多运算符 + +布尔向量现在支持更多运算符: + +```zig +test "boolean vector operations" { + const vec_a: @Vector(4, bool) = .{ true, false, true, false }; + const vec_b: @Vector(4, bool) = .{ false, true, true, false }; + + const and_result = vec_a & vec_b; + const or_result = vec_a | vec_b; + const xor_result = vec_a ^ vec_b; + const not_result = ~vec_a; +} +``` + +### 内联汇编:类型化的破坏描述符 + +内联汇编现在支持类型化的 clobber 列表: + +```zig +// 旧代码 +asm volatile ("mov %[src], %[dst]" + : [dst] "=r" (dst) + : [src] "r" (src) + : "memory" // 字符串形式 +); +``` + +⬇️ + +```zig +// 新代码 +asm volatile ("mov %[src], %[dst]" + : [dst] "=r" (dst) + : [src] "r" (src) + : .memory // 类型化形式 +); +``` + +### 允许 `@ptrCast` 从单项指针到切片的转换 + +现在可以使用 `@ptrCast` 将单项指针转换为切片: + +```zig +test "ptrCast to slice" { + var value: u32 = 42; + const ptr: *u32 = &value; + + // 新功能:将单项指针转换为切片 + const slice: []u32 = @ptrCast(ptr); + + std.testing.expect(slice[0] == 42); +} +``` + +### 对 `undefined` 进行算术运算的新规则 + +`undefined` 值的算术运算规则发生了变化: + +```zig +test "undefined arithmetic" { + const a: i32 = undefined; + const b: i32 = 10; + + // 任何与 undefined 的运算都返回 undefined + const result = a + b; // result 是 undefined + _ = result; + + // 更安全的做法 + const safe_a: i32 = 0; // 显式初始化 + const safe_result = safe_a + b; + std.testing.expect(safe_result == 10); +} +``` + +### 对从整数到浮点数的有损转换发出错误 + +现在对于可能导致精度损失的转换会发出编译错误: + +```zig +test "lossy integer to float conversion" { + const large_int: u64 = 0x1FFFFFFFFFFFFF; // 53 位 + + // 这将产生编译错误,因为 f64 只有 52 位尾数 + // const float_val: f64 = @floatFromInt(large_int); // 错误! + + // 需要显式使用有损转换 + const float_val: f64 = @floatFromInt(@as(u53, @truncate(large_int))); + + std.debug.print("Float: {}\n", .{float_val}); +} +``` + +## 标准库 + +### Writergate + +这是本次更新中最重大的破坏性更改,原有的 `std.io` 中的读写器接口被完全重新设计。 + +#### 动机 + +旧的 I/O 系统存在以下问题: + +- 泛型接口导致编译时间过长 +- 缓冲区管理不一致 +- 性能不佳,存在不必要的内存拷贝 +- 接口复杂,难以优化 + +#### 适配器 API + +新的设计引入了适配器模式: + +```zig +// 旧的泛型接口 +fn processData(reader: anytype, writer: anytype) !void { + var buffer: [1024]u8 = undefined; + while (true) { + const bytes_read = try reader.read(&buffer); + if (bytes_read == 0) break; + try writer.writeAll(buffer[0..bytes_read]); + } +} +``` + +⬇️ + +```zig +// 新的适配器接口 +fn processData(reader: std.Io.Reader, writer: std.Io.Writer) !void { + var buffer: [1024]u8 = undefined; + while (true) { + const bytes_read = try reader.read(&buffer); + if (bytes_read == 0) break; + try writer.writeAll(buffer[0..bytes_read]); + } +} + +// 使用时需要适配器 +const file = try std.fs.cwd().openFile("input.txt", .{}); +defer file.close(); + +const stdout = std.io.getStdOut(); + +try processData( + file.reader().adapter(), // 适配器转换 + stdout.writer().adapter(), // 适配器转换 +); +``` + +### 新的 `std.Io.Writer` 和 `std.Io.Reader` API + +新的 API 采用**非泛型设计**: + +```zig +// std.Io.Writer 的定义 +pub const Writer = struct { + ptr: *anyopaque, + vtable: *const VTable, + + pub const VTable = struct { + write: *const fn (*anyopaque, []const u8) anyerror!usize, + writeAll: *const fn (*anyopaque, []const u8) anyerror!void, + writeByte: *const fn (*anyopaque, u8) anyerror!void, + }; + + pub fn write(self: Writer, bytes: []const u8) !usize { + return self.vtable.write(self.ptr, bytes); + } + + pub fn writeAll(self: Writer, bytes: []const u8) !void { + return self.vtable.writeAll(self.ptr, bytes); + } +}; +``` + +#### `std.fs.File.Reader` 和 `std.fs.File.Writer` + +文件 I/O 的使用方式也发生了变化: + +```zig +// 旧代码 +const file = try std.fs.cwd().openFile("data.txt", .{}); +defer file.close(); + +const reader = file.reader(); +var buffer: [1024]u8 = undefined; +const bytes_read = try reader.read(&buffer); +``` + +⬇️ + +```zig +// 新代码 +const file = try std.fs.cwd().openFile("data.txt", .{}); +defer file.close(); + +// 方式 1:直接使用文件方法 +var buffer: [1024]u8 = undefined; +const bytes_read = try file.read(&buffer); + +// 方式 2:使用新的 Reader 接口 +const reader = file.reader(); +const io_reader = reader.adapter(); +const bytes_read2 = try io_reader.read(&buffer); +``` + +#### 升级 `std.io.getStdOut().writer().print()` + +标准输出的使用方式也需要调整: + +```zig +// 旧代码 +const stdout = std.io.getStdOut().writer(); +try stdout.print("Hello, {s}!\n", .{"World"}); +``` + +⬇️ + +```zig +// 新代码 +// 方式 1:使用 std.debug.print(推荐) +std.debug.print("Hello, {s}!\n", .{"World"}); + +// 方式 2:使用新的 Writer 接口 +const stdout = std.io.getStdOut(); +const writer = stdout.writer().adapter(); +try writer.print("Hello, {s}!\n", .{"World"}); + +// 方式 3:直接使用文件方法 +const stdout = std.io.getStdOut(); +try stdout.writeAll("Hello, World!\n"); +``` + +#### 重构 `std.compress.flate` + +压缩相关的代码也需要大量修改: + +```zig +// 旧代码 +var deflate_stream = std.compress.flate.deflateStream(allocator, writer); +defer deflate_stream.deinit(); +try deflate_stream.writer().writeAll(data); +try deflate_stream.finish(); +``` + +⬇️ + +```zig +// 新代码 +var deflate_stream = std.compress.flate.DeflateStream.init(allocator, writer.adapter()); +defer deflate_stream.deinit(); +try deflate_stream.writeAll(data); +try deflate_stream.finish(); +``` + +#### 删除 `CountingWriter` + +`CountingWriter` 被删除,需要手动计数: + +```zig +// 旧代码 +var counting_writer = std.io.countingWriter(base_writer); +``` + +⬇️ + +```zig +// 新代码 - 需要手动计数 +var bytes_written: usize = 0; +``` + +#### 删除 `BufferedWriter` + +`BufferedWriter` 被重构: + +```zig +// 旧代码 +var buffered_writer = std.io.bufferedWriter(base_writer); +``` + +⬇️ + +```zig +// 新代码 +var buffer: [4096]u8 = undefined; +var buffered_writer = std.io.BufferedWriter(4096, @TypeOf(base_writer)).init(base_writer); +``` + +### 调用 `format` 方法需要使用 `{f}` + +现在调用自定义的 `format` 方法需要使用 `{f}` 格式说明符: + +```zig +const Point = struct { + x: f32, + y: f32, + + pub fn format(self: Point, writer: anytype) !void { + try writer.print("Point({d}, {d})", .{ self.x, self.y }); + } +}; + +// 使用时必须使用 {f} +const point = Point{ .x = 1.0, .y = 2.0 }; +std.debug.print("{f}\n", .{point}); // 注意使用 {f} +``` + +### `format` 方法不再使用格式字符串或选项 + +格式化方法的签名已经简化: + +```zig +// 旧代码 +const Point = struct { + x: f32, + y: f32, + + pub fn format( + self: Point, + comptime fmt: []const u8, // 被移除 + options: std.fmt.FormatOptions, // 被移除 + writer: anytype, + ) !void { + _ = fmt; + _ = options; + try writer.print("Point({d}, {d})", .{ self.x, self.y }); + } +}; +``` + +⬇️ + +```zig +// 新代码 +const Point = struct { + x: f32, + y: f32, + + pub fn format( + self: Point, + writer: anytype, // 只保留 writer 参数 + ) !void { + try writer.print("Point({d}, {d})", .{ self.x, self.y }); + } +}; +``` + +### 格式化打印不再处理 Unicode + +Unicode 处理被移除,需要手动处理: + +```zig +// 旧代码 +std.debug.print("你好,{s}!\n", .{"世界"}); // 自动处理 Unicode +``` + +⬇️ + +```zig +// 新代码 - 需要手动处理 Unicode +const message = "你好,世界!"; +std.debug.print("{s}\n", .{message}); // 仍然可以显示,但不保证所有 Unicode 处理 +``` + +### 新的格式化打印说明符 + +新增了一些格式化说明符: + +```zig +const value: u32 = 255; + +// 新的格式化选项 +std.debug.print("{d}\n", .{value}); // 十进制:255 +std.debug.print("{x}\n", .{value}); // 十六进制:ff +std.debug.print("{X}\n", .{value}); // 大写十六进制:FF +std.debug.print("{o}\n", .{value}); // 八进制:377 +std.debug.print("{b}\n", .{value}); // 二进制:11111111 + +// 浮点数格式化 +const pi: f64 = 3.14159; +std.debug.print("{d:.2}\n", .{pi}); // 保留两位小数:3.14 +std.debug.print("{e}\n", .{pi}); // 科学计数法:3.14159e+00 + +// 指针和切片 +const ptr: *u32 = &value; +const slice: []const u8 = "hello"; +std.debug.print("{*}\n", .{ptr}); // 指针地址 +std.debug.print("{s}\n", .{slice}); // 字符串 +std.debug.print("{any}\n", .{slice}); // 通用格式化 +``` + +### 去泛型化链表 + +链表类型也进行了重构: + +```zig +// 旧代码 +const Node = std.SinglyLinkedList(i32).Node; +var list = std.SinglyLinkedList(i32){}; +var node = Node{ .data = 42 }; +list.prepend(&node); +``` + +⬇️ + +```zig +// 新代码 +const SinglyLinkedList = std.SinglyLinkedList; +const Node = SinglyLinkedList.Node; + +var list: SinglyLinkedList = .{}; +var node = Node{ .data = @as(*anyopaque, @ptrCast(&@as(i32, 42))) }; +list.prepend(&node); + +// 或者使用新的 API +var typed_list = std.DoublyLinkedList(i32){}; +var typed_node = std.DoublyLinkedList(i32).Node{ .data = 42 }; +typed_list.append(&typed_node); +``` + +### `std.Progress` 支持进度条转义码 + +进度条系统得到了增强,支持更多的终端转义码。 + +### HTTP 客户端和服务器 + +标准库新增了 HTTP 支持: + +```zig +// HTTP 客户端示例 +const std = @import("std"); + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + var client = std.http.Client{ .allocator = allocator }; + defer client.deinit(); + + const uri = std.Uri.parse("https://httpbin.org/get") catch unreachable; + + var headers = std.http.Headers{ .allocator = allocator }; + defer headers.deinit(); + + try headers.append("User-Agent", "Zig HTTP Client"); + + var request = try client.open(.GET, uri, headers, .{}); + defer request.deinit(); + + try request.send(.{}); + try request.wait(); + + const body = try request.reader().readAllAlloc(allocator, 8192); + defer allocator.free(body); + + std.debug.print("Response: {s}\n", .{body}); +} +``` + +### TLS 客户端 + +内置 TLS 支持: + +```zig +// TLS 连接示例 +const std = @import("std"); + +pub fn main() !void { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + const allocator = gpa.allocator(); + + const address = try std.net.Address.parseIp("93.184.216.34", 443); // example.com + const stream = try std.net.tcpConnectToAddress(address); + defer stream.close(); + + var tls_client = try std.crypto.tls.Client.init(stream, .{ + .host = "example.com", + .allocator = allocator, + }); + defer tls_client.deinit(); + + const request = "GET / HTTP/1.1\r\nHost: example.com\r\n\r\n"; + try tls_client.writeAll(request); + + var buffer: [4096]u8 = undefined; + const bytes_read = try tls_client.read(&buffer); + std.debug.print("Response: {s}\n", .{buffer[0..bytes_read]}); +} +``` + +### `ArrayList`:将非托管模式设为默认 + +这是一个重大的破坏性更改。`std.ArrayList` 现在默认采用 **非托管 (unmanaged)** 模式: + +```zig +// 旧代码 +const std = @import("std"); + +fn oldArrayListExample(allocator: std.mem.Allocator) !void { + var list = std.ArrayList(i32).init(allocator); + defer list.deinit(); + + try list.append(42); + try list.appendSlice(&[_]i32{ 1, 2, 3 }); + + for (list.items) |item| { + std.debug.print("{d} ", .{item}); + } +} +``` + +⬇️ + +```zig +// 新代码 +const std = @import("std"); + +fn newArrayListExample(allocator: std.mem.Allocator) !void { + // 方式 1:使用新的 ArrayListUnmanaged + var list: std.ArrayListUnmanaged(i32) = .empty; + defer list.deinit(allocator); + + try list.append(allocator, 42); + try list.appendSlice(allocator, &[_]i32{ 1, 2, 3 }); + + for (list.items) |item| { + std.debug.print("{d} ", .{item}); + } +} + +// 方式 2:使用别名保持兼容性 +fn compatibilityExample(allocator: std.mem.Allocator) !void { + // ArrayList 现在是 ArrayListUnmanaged 的别名 + const ArrayList = std.ArrayListUnmanaged; + var list: ArrayList(i32) = .empty; + defer list.deinit(allocator); + + try list.append(allocator, 42); +} + +// 方式 3:使用新的初始化方法 +fn newInitExample(allocator: std.mem.Allocator) !void { + var list = std.ArrayList(i32).init(allocator); // 仍然可用,但已弃用 + defer list.deinit(); + + // 或者使用新的方式 + var new_list: std.ArrayList(i32) = .{}; + defer new_list.deinit(allocator); + + try new_list.append(allocator, 42); +} +``` + +其他容器类型也发生了类似的变化: + +```zig +// HashMap +var map: std.HashMapUnmanaged([]const u8, i32, std.hash_map.StringContext, 80) = .{}; +defer map.deinit(allocator); + +try map.put(allocator, "key", 42); +const value = map.get("key"); + +// ArrayHashMap +var array_map: std.ArrayHashMapUnmanaged([]const u8, i32, std.hash_map.StringContext, false) = .{}; +defer array_map.deinit(allocator); + +try array_map.put(allocator, "key", 42); + +// PriorityQueue +var pq: std.PriorityQueueUnmanaged(i32, void, compareInts) = .{}; +defer pq.deinit(allocator); + +try pq.add(allocator, 42); + +fn compareInts(context: void, a: i32, b: i32) std.math.Order { + _ = context; + return std.math.order(a, b); +} +``` + +### 环形缓冲区 + +新增了环形缓冲区类型: + +```zig +const RingBuffer = std.RingBuffer; + +// 创建环形缓冲区 +var buffer: [16]u8 = undefined; +var ring = RingBuffer.init(&buffer); + +// 写入数据 +const data = "Hello, World!"; +const written = ring.write(data); +std.debug.print("Written {} bytes\n", .{written}); + +// 读取数据 +var read_buffer: [32]u8 = undefined; +const read_count = ring.read(&read_buffer); +std.debug.print("Read: {s}\n", .{read_buffer[0..read_count]}); +``` + +### 移除 `BoundedArray` + +`BoundedArray` 被移除,建议使用其他替代方案: + +```zig +// 旧代码 +var bounded = std.BoundedArray(i32, 10).init(0); +try bounded.append(42); +``` + +⬇️ + +```zig +// 新代码 - 使用 ArrayList 或数组 +var list: std.ArrayListUnmanaged(i32) = .empty; +defer list.deinit(allocator); + +// 或者使用固定大小数组 +var array: [10]i32 = undefined; +var count: usize = 0; + +if (count < array.len) { + array[count] = 42; + count += 1; +} +``` + +### 删除和弃用 + +本次更新中删除和弃用了多个 API,需要使用新的替代方案。 + +## 构建系统 + +### 移除已弃用的隐式根模块 + +构建系统中已移除对隐式根模块的支持,需要在构建脚本中明确指定模块: + +```zig +// 旧的 build.zig +pub fn build(b: *std.Build) void { + const exe = b.addExecutable(.{ + .name = "app", + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }); +} +``` + +⬇️ + +```zig +// 新的 build.zig +pub fn build(b: *std.Build) void { + const exe = b.addExecutable(.{ + .name = "app", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + }), + }); +} +``` + +### macOS 文件系统监视 + +在 macOS 上,构建系统现在支持文件系统监视功能,能够在文件更改时自动触发重建: + +```bash +# 启用文件系统监视 +zig build --watch + +# 设置去抖动时间(默认50ms) +zig build --watch --debounce 100 +``` + +### Web 界面和即时报告 + +构建系统现在支持 Web 界面和详细的即时报告功能。 + +## 编译器 + +### x86 后端 + +在 **调试编译** 默认为 **x86 后端** 的情况下,其速度提高了 5 倍。这也是本次更新最显著的性能改进: + +```bash +# 使用新的 x86 后端(默认) +zig build -Doptimize=Debug + +# 如果需要使用 LLVM 后端 +zig build -Doptimize=Debug -fLLVM +``` + +### aarch64 后端 + +**aarch64 后端** 的开发也在稳步推进,为 ARM 平台提供更好的支持。 + +### 增量编译 + +增量编译功能得到了改进: + +```bash +# 启用增量编译 +zig build -fincremental + +# 结合文件系统监视 +zig build -fincremental --watch + +# 仅检查编译错误(不生成二进制文件) +zig build -fincremental -fno-emit-bin --watch +``` + +### 多线程代码生成 + +编译器现在支持多线程代码生成: + +```bash +# 控制编译线程数 +zig build -j4 # 使用 4 个线程 +zig build -j # 使用所有可用 CPU 核心 + +# 禁用多线程编译 +zig build -j1 +``` + +### 允许在模块级别配置 UBSan 模式 + +现在可以在模块级别配置 UBSan(未定义行为检测器): + +```zig +// build.zig 中的配置 +const exe = b.addExecutable(.{ + .name = "app", + .root_module = b.createModule(.{ + .root_source_file = b.path("src/main.zig"), + .target = target, + .optimize = optimize, + .sanitize_c = true, // 启用 C 代码的 UBSan + }), +}); + +// 或者使用命令行 +zig build -Dsanitize-c +``` + +### 将测试编译为目标文件 + +现在可以将测试编译为目标文件而不是可执行文件: + +```bash +# 将测试编译为 .o 文件 +zig test src/main.zig --object + +# 将测试编译为静态库 +zig test src/main.zig --library + +# 将测试编译为动态库 +zig test src/main.zig --dynamic-library +``` + +### Zig 初始化 + +`zig init` 命令得到了改进: + +```bash +# 创建新项目 +zig init + +# 创建库项目 +zig init --lib + +# 创建可执行项目 +zig init --exe + +# 指定项目名称 +zig init --name my-project + +# 在现有目录中初始化 +zig init . +``` + +## 链接器 + +链接器得到了多项改进和优化。 + +## 模糊测试器 + +Zig 0.15.1 集成了一个内置的模糊测试器: + +```bash +# 启动模糊测试 +zig build test --fuzz + +# 指定端口 +zig build test --fuzz --port 8080 + +# 指定测试时间 +zig build test --fuzz --timeout 60 +``` + +```zig +// 模糊测试例子 +test "fuzz string parsing" { + const input_bytes = std.testing.fuzzInput(.{}); + + // 测试字符串解析函数 + const result = parseString(input_bytes); + + // 确保不会崩溃 + _ = result catch |err| { + // 预期的错误可以忽略 + if (err == error.InvalidInput) return; + return err; + }; +} + +fn parseString(input: []const u8) ![]const u8 { + if (input.len == 0) return error.InvalidInput; + // 解析逻辑... + return input; +} +``` + +## 错误修复 + +本次发布修复了大量错误。 + +## 本次发布包含的错误 + +Zig 目前仍存在一些已知的 bugs,包括一些编译错误。 + +## 工具链 + +### LLVM 20 + +本次更新升级到 LLVM 20,带来了以下改进: + +- 更好的优化支持 +- 新的目标架构支持 +- 改进的调试信息生成 +- 更好的 C++ 交互性 + +### 在交叉编译时支持动态链接的 FreeBSD libc + +```bash +# 交叉编译到 FreeBSD +zig build -Dtarget=x86_64-freebsd-gnu +zig build -Dtarget=aarch64-freebsd-gnu + +# 使用动态链接的 libc +zig build -Dtarget=x86_64-freebsd-gnu -Ddynamic-linker +``` + +### 在交叉编译时支持动态链接的 NetBSD libc + +```bash +# 交叉编译到 NetBSD +zig build -Dtarget=x86_64-netbsd-gnu +zig build -Dtarget=aarch64-netbsd-gnu + +# 使用 NetBSD 系统 libc +zig cc -target x86_64-netbsd-gnu program.c +``` + +### glibc 2.42 + +升级到 glibc 2.42,并支持静态链接本地 glibc: + +```bash +# 使用系统 glibc 静态链接 +zig build -Dtarget=native-linux-gnu -Dlinkage=static + +# 指定 glibc 版本 +zig build -Dtarget=x86_64-linux-gnu.2.42 +``` + +#### 允许静态链接本机 glibc + +现在可以静态链接本机系统的 glibc。 + +### MinGW-w64 + +MinGW-w64 工具链得到了更新: + +```bash +# Windows 交叉编译 +zig build -Dtarget=x86_64-windows-gnu +zig build -Dtarget=aarch64-windows-gnu + +# 使用 MinGW-w64 工具链 +zig cc -target x86_64-windows-gnu program.c +``` + +### zig libc + +`zig libc` 命令得到了增强: + +```bash +# 查看当前目标的 libc 配置 +zig libc + +# 查看指定目标的 libc +zig libc -target x86_64-linux-gnu + +# 查看所有可用的 libc +zig targets | grep libc +``` + +### zig cc + +`zig cc` 作为 C 编译器的功能得到了增强: + +```bash +# 更好的 GCC 兼容性 +zig cc -std=c11 -O2 program.c + +# 支持更多编译选项 +zig cc -march=native -mtune=native program.c + +# 更好的错误报告 +zig cc -Wall -Wextra program.c +``` + +### zig objcopy 回归 + +`zig objcopy` 命令存在一些回归问题,正在修复中。 + +## 路线图 + +### I/O 作为接口 + +I/O 系统将继续作为接口进行发展和完善。 + +## 升级建议 + +由于此次更新包含多项破坏性更改,建议开发者在升级至 0.15.1 版本时: + +### 升级步骤 + +1. **备份现有代码**:在开始升级之前做好备份 + +2. **分步骤进行**: + - 首先处理 `usingnamespace` 的移除 + - 然后处理 I/O 系统的重构 + - 最后处理 ArrayList 等容器的变更 + +3. **使用编译器检查**: + + ```bash + # 检查编译错误 + zig build-exe src/main.zig + + # 使用新的 x86 后端加速编译 + zig build -fno-LLVM + ``` + +4. **测试全面性**:确保所有功能在新版本下正常运行 +5. **利用新特性**: + - 使用新的 x86 后端提高编译速度 + - 使用文件系统监视功能 + - 尝试增量编译 + +### 常见问题和解决方案 + +1. **I/O 代码编译错误**:参考上面的 Writergate 部分 +2. **`usingnamespace` 错误**:使用显式导入替代 +3. **ArrayList 错误**:改为使用 ArrayListUnmanaged +4. **格式化错误**:更新 format 方法签名 + +## 注意事项 + +- 这次升级的破坏性更改较多,建议在测试环境中进行充分测试 +- I/O 接口的重构可能需要较多的代码调整工作 +- 新的性能改进主要体现在编译速度上 +- 文件系统监视功能有助于提高开发效率 + +完整的发布说明可在 [Zig 官方网站](https://ziglang.org/download/0.15.1/release-notes.html) 查看。