diff --git a/course/code/16/hello_world.zig b/course/code/16/hello_world.zig index 35a6ec9f..e5555e34 100644 --- a/course/code/16/hello_world.zig +++ b/course/code/16/hello_world.zig @@ -1,13 +1,15 @@ -pub fn main(init: std.process.Init) !void { +// 三个 struct 各自包含一段文档片段,每段都是可以直接粘贴进 src/main.zig 的完整程序。 +// 因此 std 的导入放在各 struct 内部,文件级不能再有 `const std`(否则 ambiguous reference)。 +pub fn main(init: @import("std").process.Init) !void { try One.main(); - try Two.main(init.io); - try Three.main(init.io); + try Two.main(init); + try Three.main(init); } -const std = @import("std"); - const One = struct { // #region one + const std = @import("std"); + pub fn main() !void { std.debug.print("Hello, World!\n", .{}); } @@ -16,43 +18,47 @@ const One = struct { const Two = struct { // #region two - pub fn main(io: std.Io) !void { - var stdout_buffer: [1024]u8 = undefined; - var stdout_writer = std.Io.File.stdout().writer(io, &stdout_buffer); + const std = @import("std"); + + pub fn main(init: std.process.Init) !void { + const io = init.io; + + // 传入长度为 0 的缓冲区,表示不缓冲,每次 print 都直接写出 + var stdout_writer = std.Io.File.stdout().writer(io, &.{}); const stdout = &stdout_writer.interface; - var stderr_buffer: [1024]u8 = undefined; - var stderr_writer = std.Io.File.stderr().writer(io, &stderr_buffer); + var stderr_writer = std.Io.File.stderr().writer(io, &.{}); const stderr = &stderr_writer.interface; try stdout.print("Hello {s}!\n", .{"out"}); try stderr.print("Hello {s}!\n", .{"err"}); - - try stdout.flush(); - try stderr.flush(); - } // #endregion two + } + // #endregion two }; const Three = struct { // #region three - pub fn main(io: std.Io) !void { + const std = @import("std"); + + pub fn main(init: std.process.Init) !void { + const io = init.io; + // 定义两个缓冲区 var stdout_buffer: [1024]u8 = undefined; // [!code focus] var stderr_buffer: [1024]u8 = undefined; // [!code focus] - // 获取writer句柄// [!code focus] - var stdout_writer = std.Io.File.stdout().writer(io, &stdout_buffer); + // 获取 writer 句柄 + var stdout_writer = std.Io.File.stdout().writer(io, &stdout_buffer); // [!code focus] const stdout = &stdout_writer.interface; - // 获取writer句柄// [!code focus] - var stderr_writer = std.Io.File.stderr().writer(io, &stderr_buffer); + var stderr_writer = std.Io.File.stderr().writer(io, &stderr_buffer); // [!code focus] const stderr = &stderr_writer.interface; - // 通过句柄写入buffer// [!code focus] - try stdout.print("Hello {s}!\n", .{"out"}); // [!code focus] - try stderr.print("Hello {s}!\n", .{"err"}); // [!code focus] + // 通过句柄写入 buffer + try stdout.print("Hello {s}!\n", .{"out"}); + try stderr.print("Hello {s}!\n", .{"err"}); - // 尝试刷新buffer// [!code focus] + // 把 buffer 中的内容真正刷出去 try stdout.flush(); // [!code focus] try stderr.flush(); // [!code focus] } diff --git a/course/code/release/hello_world.zig b/course/code/release/hello_world.zig index 35a6ec9f..e5555e34 100644 --- a/course/code/release/hello_world.zig +++ b/course/code/release/hello_world.zig @@ -1,13 +1,15 @@ -pub fn main(init: std.process.Init) !void { +// 三个 struct 各自包含一段文档片段,每段都是可以直接粘贴进 src/main.zig 的完整程序。 +// 因此 std 的导入放在各 struct 内部,文件级不能再有 `const std`(否则 ambiguous reference)。 +pub fn main(init: @import("std").process.Init) !void { try One.main(); - try Two.main(init.io); - try Three.main(init.io); + try Two.main(init); + try Three.main(init); } -const std = @import("std"); - const One = struct { // #region one + const std = @import("std"); + pub fn main() !void { std.debug.print("Hello, World!\n", .{}); } @@ -16,43 +18,47 @@ const One = struct { const Two = struct { // #region two - pub fn main(io: std.Io) !void { - var stdout_buffer: [1024]u8 = undefined; - var stdout_writer = std.Io.File.stdout().writer(io, &stdout_buffer); + const std = @import("std"); + + pub fn main(init: std.process.Init) !void { + const io = init.io; + + // 传入长度为 0 的缓冲区,表示不缓冲,每次 print 都直接写出 + var stdout_writer = std.Io.File.stdout().writer(io, &.{}); const stdout = &stdout_writer.interface; - var stderr_buffer: [1024]u8 = undefined; - var stderr_writer = std.Io.File.stderr().writer(io, &stderr_buffer); + var stderr_writer = std.Io.File.stderr().writer(io, &.{}); const stderr = &stderr_writer.interface; try stdout.print("Hello {s}!\n", .{"out"}); try stderr.print("Hello {s}!\n", .{"err"}); - - try stdout.flush(); - try stderr.flush(); - } // #endregion two + } + // #endregion two }; const Three = struct { // #region three - pub fn main(io: std.Io) !void { + const std = @import("std"); + + pub fn main(init: std.process.Init) !void { + const io = init.io; + // 定义两个缓冲区 var stdout_buffer: [1024]u8 = undefined; // [!code focus] var stderr_buffer: [1024]u8 = undefined; // [!code focus] - // 获取writer句柄// [!code focus] - var stdout_writer = std.Io.File.stdout().writer(io, &stdout_buffer); + // 获取 writer 句柄 + var stdout_writer = std.Io.File.stdout().writer(io, &stdout_buffer); // [!code focus] const stdout = &stdout_writer.interface; - // 获取writer句柄// [!code focus] - var stderr_writer = std.Io.File.stderr().writer(io, &stderr_buffer); + var stderr_writer = std.Io.File.stderr().writer(io, &stderr_buffer); // [!code focus] const stderr = &stderr_writer.interface; - // 通过句柄写入buffer// [!code focus] - try stdout.print("Hello {s}!\n", .{"out"}); // [!code focus] - try stderr.print("Hello {s}!\n", .{"err"}); // [!code focus] + // 通过句柄写入 buffer + try stdout.print("Hello {s}!\n", .{"out"}); + try stderr.print("Hello {s}!\n", .{"err"}); - // 尝试刷新buffer// [!code focus] + // 把 buffer 中的内容真正刷出去 try stdout.flush(); // [!code focus] try stderr.flush(); // [!code focus] } diff --git a/course/hello-world.md b/course/hello-world.md index e999dd3e..a64d68fd 100644 --- a/course/hello-world.md +++ b/course/hello-world.md @@ -60,6 +60,8 @@ Zig 本身没有内置的 `@print()` 函数,输出功能通常由标准库的 :::info 🅿️ 提示 `main` 函数的返回类型 `!void` 是一个错误联合类型。它表示该函数要么成功执行并返回 `void`(即无返回值),要么返回一个错误。 + +`main` 的参数 `init: std.process.Init` 是入口函数可选的参数形式,它携带了运行时的初始化信息,其中的 `init.io` 就是我们做 I/O 所需要的 `Io` 实例。 ::: 这段代码分别向 `stdout` 和 `stderr` 输出了信息。 @@ -67,7 +69,7 @@ Zig 本身没有内置的 `@print()` 函数,输出功能通常由标准库的 - `stdout` (标准输出):用于输出程序的正常信息。写入 `stdout` 的操作可能会失败。 - `stderr` (标准错误):用于输出错误信息。写入 `stderr` 同样可能失败,因此示例里也使用了 `try` 来处理错误。 -我们通过 `std.Io.File.stdout()` 和 `std.Io.File.stderr()` 获取标准输出和标准错误,并基于传入的 `io` 实例创建 `writer`。示例中的 `io` 一般来自入口函数 `main(init: std.process.Init)` 中的 `init.io`。 +我们通过 `std.Io.File.stdout()` 和 `std.Io.File.stderr()` 获取标准输出和标准错误,再基于 `io` 创建各自的 `writer`。这里传入的缓冲区是空的(`&.{}`),意味着不做缓冲——每一次 `print` 都会直接写出去。 ### 考虑性能:使用缓冲区 @@ -77,7 +79,11 @@ Zig 本身没有内置的 `@print()` 函数,输出功能通常由标准库的 <<<@/code/release/hello_world.zig#three -这里直接为 `stdout` 和 `stderr` 各自提供了一块固定缓冲区,`writer` 会先把内容写入缓冲区,再在 `flush` 时真正输出,从而减少系统调用。 +与上一段代码的区别只在于:这里为 `stdout` 和 `stderr` 各自提供了一块 1024 字节的缓冲区。`writer` 会先把内容写入缓冲区,直到缓冲区满或者调用 `flush` 时才真正输出,从而减少系统调用的次数。 + +::: warning ⚠️ 注意 +使用缓冲区后,**必须记得 `flush`**,否则程序结束时缓冲区里尚未写出的内容就丢失了。 +::: ## 更进一步:线程安全