diff --git a/02-language-overview-part1.md b/02-language-overview-part1.md index 470ef53..9d53f1d 100644 --- a/02-language-overview-part1.md +++ b/02-language-overview-part1.md @@ -9,7 +9,7 @@ Zig 代码如下所示: ```zig const std = @import("std"); -// This code won't compile if `main` isn't `pub` (public) +// 如果 `main` 不是 `pub` (public),此代码将无法编译 pub fn main() void { const user = User{ .power = 9001, @@ -87,7 +87,7 @@ const MAX_POWER = user.MAX_POWER 下面这行 Zig 代码是一个注释: ```zig -// This code won't compile if `main` isn't `pub` (public) +// 如果 `main` 不是 `pub` (public),此代码将无法编译 ``` Zig 没有像 C 语言中类似 `/* ... */` 的多行注释。 @@ -190,10 +190,10 @@ pub const User = struct { 方法只是普通函数,只是说可以用 `struct.method()` 方式调用。以下两种方法等价: ```zig -// call diagnose on user +// 调用 user 的 diagnose user.diagnose(); -// The above is syntactical sugar for: +// 上面代码等价于: User.diagnose(user); ``` @@ -271,11 +271,12 @@ pub fn init(name: []const u8, power: u64) User { ```zig const a = [5]i32{1, 2, 3, 4, 5}; -// we already saw this .{...} syntax with structs -// it works with arrays too +// 我们已经在结构体中使用过 .{...} 语法, +// 它也适用于数组 + const b: [5]i32 = .{1, 2, 3, 4, 5}; -// use _ to let the compiler infer the length +// 使用 _ 让编译器推导长度 const c = [_]i32{1, 2, 3, 4, 5}; ``` @@ -320,7 +321,7 @@ pub fn main() void { 为了解决这个问题,你可能会想要进行以下更改: ```zig -// replace const with var +// 将 const 替换为 var var b = a[1..end]; ``` @@ -403,7 +404,7 @@ std.debug.print("{s}'s power is {d}\n", .{user.name, user.power}); 你可能想知道上面这行代码中需要编译时执行的是什么。`print` 函数的定义要求我们的第一个参数(字符串格式)是编译时已知的: ```zig -// notice the "comptime" before the "fmt" variable +// 注意变量"fmt"前的"comptime" pub fn print(comptime fmt: []const u8, args: anytype) void { ``` diff --git a/03-language-overview-part2.md b/03-language-overview-part2.md index 7274a98..03c1ef0 100644 --- a/03-language-overview-part2.md +++ b/03-language-overview-part2.md @@ -15,12 +15,11 @@ Zig 的控制流很可能是我们所熟悉的,但它与 Zig 语言的其他 Zig 中,`if`、`else if` 和 `else` 也很常见: ```zig -// std.mem.eql does a byte-by-byte comparison -// for a string it'll be case sensitive +// std.mem.eql 将逐字节进行比较,对于字符串来说它是大小写敏感的。 if (std.mem.eql(u8, method, "GET") or std.mem.eql(u8, method, "HEAD")) { - // handle a GET request + // 处理 GET 请求 } else if (std.mem.eql(u8, method, "POST")) { - // handle a POST request + // 处理 POST 请求 } else { // ... } @@ -156,10 +155,11 @@ while (i < src.len) { var i: usize = 0; var escape_count: usize = 0; -// this part +// 改写后的 while (i < src.len) : (i += 1) { if (src[i] == '\\') { // +1 here, and +1 above == +2 + // 这里 +1,上面也 +1,相当于 +2 i += 1; escape_count += 1; } @@ -199,7 +199,7 @@ const personality_analysis = blk: { 枚举是带有标签的整数常量。它们的定义很像结构体: ```zig -// could be "pub" +// 可以是 "pub" 的 const Status = enum { ok, bad, @@ -341,9 +341,8 @@ if (home) |h| { ```zig const h = home orelse "unknown" -// or maybe -// exit our function +// 或直接返回函数 const h = home orelse return; ``` @@ -373,8 +372,8 @@ std.crypto.random.bytes(&pseudo_uuid); Zig 中错误处理功能十分简单、实用。这一切都从错误集(error sets)开始,错误集的使用方式类似于枚举: ```zig -// Like our struct in Part 1, OpenError can be marked as "pub" -// to make it accessible outside of the file it is defined in +// 与第 1 部分中的结构一样,OpenError 也可以标记为 "pub"。 +// 使其可以在其定义的文件之外访问 const OpenError = error { AccessDenied, NotFound, @@ -475,7 +474,7 @@ try action(req, res); 函数同时返回可选类型与错误联合类型的情况并不少见。在推导错误集的情况下,形式如下: ```zig -// load the last saved game +// 载入上次保存的游戏 pub fn loadLast() !?Save { // TODO return null; diff --git a/07-heap-memory-and-allocator.md b/07-heap-memory-and-allocator.md index 812f689..02c6cee 100644 --- a/07-heap-memory-and-allocator.md +++ b/07-heap-memory-and-allocator.md @@ -140,7 +140,7 @@ fn allocLower(allocator: Allocator, str: []const u8) ![]const u8 { 上面的代码没问题。但以下用法不是: ```zig -// For this specific code, we should have used std.ascii.eqlIgnoreCase +// 对于这个特定的代码,我们应该使用 std.ascii.eqlIgnoreCase fn isSpecial(allocator: Allocator, name: [] const u8) !bool { const lower = try allocLower(allocator, name); return std.mem.eql(u8, lower, "admin"); @@ -211,7 +211,7 @@ pub const User = struct { 在这种情况下,返回一个 `User`可能更有意义。但有时你会希望函数返回一个指向它所创建的东西的指针。当你想让生命周期不受调用栈的限制时,你就会这样做。为了解决上面的悬空指针问题,我们可以使用`create` 方法: ```zig -// our return type changed, since init can now fail +// 我们的返回类型改变了,因为 init 现在可以失败了 // *User -> !*User fn init(allocator: std.mem.Allocator, id: u64, power: i32) !*User{ var user = try allocator.create(User); @@ -284,7 +284,7 @@ pub fn main() !void { const T = std.heap.GeneralPurposeAllocator(.{}); var gpa = T{}; -// is the same as: +// 等同于: var gpa = std.heap.GeneralPurposeAllocator(.{}){}; ``` @@ -406,12 +406,12 @@ Test [1/1] test.IntList: add... [gpa] (err): memory address 0x101154000 leaked: 此处有多个内存泄漏。幸运的是,测试分配器准确地告诉我们泄漏的内存是在哪里分配的。你现在能发现泄漏了吗?如果没有,请记住,通常情况下,每个 `alloc` 都应该有一个相应的 `free`。我们的代码在 `deinit` 中调用 `free` 一次。然而在 `init` 中 `alloc` 被调用一次,每次调用 `add` 并需要更多空间时也会调用 `alloc`。每次我们 `alloc` 更多空间时,都需要 `free` 之前的 `self.items`。 ```zig -// existing code +// 现有的代码 var larger = try self.allocator.alloc(i64, len * 2); @memcpy(larger[0..len], self.items); -// Added code -// free the previous allocation +// 添加的代码 +// 释放先前分配的内存 self.allocator.free(self.items); ``` @@ -490,8 +490,9 @@ const aa = arena.allocator(); var list = try IntList.init(aa); -// I'm honestly torn on whether or not we should call list.deinit. -// Technically, we don't have to since we call defer arena.deinit() above. +// 说实话,我很纠结是否应该调用 list.deinit。 +// 从技术上讲,我们不必这样做,因为我们在上面调用了 defer arena.deinit()。 + defer list.deinit(); ... diff --git a/09-coding-in-zig.md b/09-coding-in-zig.md index b358226..9bcc516 100644 --- a/09-coding-in-zig.md +++ b/09-coding-in-zig.md @@ -154,7 +154,7 @@ const User = struct { 上述代码虽然区分大小写,但无论我们如何完美地输入 `Leto`,`contains` 总是返回 `false`。让我们通过遍历 `lookup` 打印其值来调试一下: ```zig -// Place this code after the while loop +// 将这段代码放在 while 循环之后 var it = lookup.iterator(); while (it.next()) |kv| { @@ -184,7 +184,7 @@ false 对于上述代码,实际上只有一种解决方案:我们的 `lookup` 必须拥有键的所有权。我们需要添加一行并修改另一行: ```zig -// replace the existing lookup.put with these two lines +// 用这两行替换现有的 lookup.put const owned_name = try allocator.dupe(u8, name); // name -> owned_name @@ -198,9 +198,7 @@ try lookup.put(owned_name, .{.power = i}); 唯一的解决办法就是自己释放键值。在这一点上,创建我们自己的 `UserLookup` 类型并在 `deinit` 函数中封装这一清理逻辑可能会比较合理。一种简单的改法: ```zig -// replace the existing: -// defer lookup.deinit(); -// with: +// 用以下的代码替换现有的 defer lookup.deinit(); defer { var it = lookup.keyIterator(); while (it.next()) |key| { @@ -367,9 +365,8 @@ pub fn main() !void { `anytype` 的一个最大缺点就是文档。下面是我们用过几次的 `std.json.stringify` 函数的签名: ```zig -// I **hate** multi-line function definitions -// But I'll make an exception for a guide which -// you might be reading on a small screen. +// 我**讨厌**多行函数定义 +// 不过,鉴于你可能在小屏幕上阅读这个指南,因此这里破一次例。 fn stringify( value: anytype, @@ -456,7 +453,7 @@ zig build install -Doptimize=ReleaseSmall -Dtarget=x86_64-windows-gnu 除了默认的『安装』步骤外,可执行文件通常还会增加两个步骤:『运行』和『测试』。一个库可能只有一个『测试』步骤。对于基本的无参数即可运行的程序来说,只需要在构建文件的最后添加四行: ```zig -// add after: b.installArtifact(exe); +// 在这行代码后添加下面的代码: b.installArtifact(exe); const run_cmd = b.addRunArtifact(exe); run_cmd.step.dependOn(b.getInstallStep()); @@ -501,8 +498,7 @@ Zig 的内置软件包管理器相对较新,因此存在一些缺陷。虽然 首先,新建一个名为 `calc` 的文件夹并创建三个文件。第一个是 `add.zig`,内容如下: ```zig -// Oh, a hidden lesson, look at the type of b -// and the return type!! +// 哦,下面的函数定义中有语法之前没讲过,看看 b 的类型和返回类型!! pub fn add(a: anytype, b: @TypeOf(a)) @TypeOf(a) { return a + b; @@ -555,8 +551,8 @@ pub fn build(b: *std.Build) !void { 回到我们的 `learning`项目和之前创建的 `build.zig`。首先,我们将添加本地 `calc` 作为依赖项。我们需要添加三项内容。首先,我们将创建一个指向 `calc.zig`的模块: ```zig -// You can put this near the top of the build -// function, before the call to addExecutable. +// 你可以把这些代码放在构建函数的顶部, +// 即调用 addExecutable 之前。 const calc_module = b.addModule("calc", .{ .source_file = .{ .path = "PATH_TO_CALC_PROJECT/calc.zig" }, @@ -572,7 +568,7 @@ const exe = b.addExecutable(.{ .optimize = optimize, .root_source_file = .{ .path = "learning.zig" }, }); -// add this +// 添加这些代码 exe.addModule("calc", calc_module); b.installArtifact(exe); @@ -583,7 +579,7 @@ const tests = b.addTest(.{ .optimize = optimize, .root_source_file = .{ .path = "learning.zig" }, }); -// add this +// 添加这行代码 tests.addModule("calc", calc_module); ``` @@ -625,12 +621,12 @@ _ = b.addModule("calc", .{ 要使用这一依赖关系,我们需要对 `build.zig` 进行一处修改: ```zig -// replace this: +// 将这些代码: const calc_module = b.addModule("calc", .{ .source_file = .{ .path = "calc/calc.zig" }, }); -// with this: +// 替换成: const calc_dep = b.dependency("calc", .{.target = target,.optimize = optimize}); const calc_module = calc_dep.module("calc"); ```