Skip to content

Commit 7acbc1a

Browse files
authored
fix: format heading ids (#74)
1 parent de38bdc commit 7acbc1a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+467
-312
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ zig-cache/
88
zig-out/
99

1010
.cache_ggshield
11+
.vscode
12+
old/

content/contributing.smd

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文
1111
1. 供稿,分享自己使用 Zig 的心得,方式见下文
1212
2. 改进 zigcc 组织下的开源项目,这是 [open issues](https://ask.ziglang.cc/github)
1313

14-
# [供稿方式]($section.id('contribute'))
14+
# [供稿方式]($heading.id('contribute'))
1515

1616
1. Fork 仓库 https://github.com/zigcc/zigcc.github.io
1717
2. 在 `content/post` 内添加自己的文章(smd格式),文件命名为: `${YYYY}-${MM}-${DD}-${SLUG}.smd`
@@ -31,20 +31,20 @@ Zig 中文社区是一个开放的组织,我们致力于推广 Zig 在中文
3131
---
3232
```
3333

34-
# [本地预览]($section.id('本地预览'))
34+
# [本地预览]($heading.id('local-preview'))
3535

3636
首先你得安装 `zine`,安装方法见 [Quick Start](https://zine-ssg.io/quickstart/),之后就可以通过执行 `zine` 命令来预览你的文章。
3737

3838
```bash
3939
zine
4040
```
4141

42-
# [发布平台]($section.id('publishing-platform'))
42+
# [发布平台]($heading.id('publishing-platform'))
4343

4444
- [ZigCC 网站](https://ziglang.cc)
4545
- [ZigCC 公众号](https://github.com/zigcc/.github/raw/main/zig_mp.png)
4646

47-
# [网站更新日志]($section.id('changelog'))
47+
# [网站更新日志]($heading.id('changelog'))
4848

4949
- **2025-06-30:** 切换到 [zine](https://zine-ssg.io/)
5050
- **2024-08-18:** 切换主题 [docsy](https://github.com/google/docsy)

content/learn/coding-in-zig.smd

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
在介绍了 Zig 语言的大部分内容之后,我们将对一些主题进行回顾,并展示几种使用 Zig 编程时一些实用的技巧。在此过程中,我们将介绍更多的标准库,并介绍一些稍复杂些的代码片段。
1212

13-
# [悬空指针 Dangling Pointers]($section.id('dangling-pointers'))
13+
# [悬空指针 Dangling Pointers]($heading.id('dangling-pointers'))
1414

1515
我们首先来看看更多关于悬空指针的例子。这似乎是一个奇怪的问题,但如果你之前主要使用带垃圾回收的语言,这可能是你学习 Zig 最大的障碍。
1616

@@ -105,7 +105,7 @@ const User = struct {
105105

106106
如果把所有东西都放在一个函数中,再加上一个像 `User` 这样的小值,这仍然像是一个人为制造的问题。我们需要一个能让数据所有权成为当务之急的例子。
107107

108-
# [所有权 Ownership]($section.id('ownership'))
108+
# [所有权 Ownership]($heading.id('ownership'))
109109

110110
我喜欢哈希表(HashMap),因为这是每个人都知道并且会经常使用的结构。它们有很多不同的用例,其中大部分你可能都用过。虽然哈希表可以用在一个短期查找的地方,但通常用于长期查找,因此插入其内的值需要同样长的生命周期。
111111

@@ -218,7 +218,7 @@ defer {
218218

219219
我保证,关于悬挂指针和内存管理的讨论已经结束了。我们所讨论的内容可能还不够清晰或过于抽象。当你有更实际的问题需要解决时,再重新讨论这个问题也不迟。不过,如果你打算编写任何稍具规模(non-trivial)的程序,这几乎肯定是你需要掌握的内容。当你觉得可以的时候,我建议你参考上面这个示例,并自己动手实践一下。引入一个 `UserLookup` 类型来封装我们必须做的所有内存管理。尝试使用 `*User` 代替 `User`,在堆上创建用户,然后像处理键那样释放它们。编写覆盖新结构的测试,使用 `std.testing.allocator` 确保不会泄漏任何内存。
220220

221-
# [ArrayList]($section.id('arraylist'))
221+
# [ArrayList]($heading.id('arraylist'))
222222

223223
现在你可以忘掉我们的 `IntList` 和我们创建的通用替代方案了。Zig 标准库中有一个动态数组实现:`std.ArrayList(T)`。
224224

@@ -313,7 +313,7 @@ pub fn main() !void {
313313
}
314314
```
315315

316-
# [Anytype]($section.id('anytype'))
316+
# [Anytype]($heading.id('anytype'))
317317

318318
在[语言概述的第一部分](language-overview-1)中,我们简要介绍了 `anytype`。这是一种非常有用的编译时 duck 类型。下面是一个简单的 logger:
319319

@@ -383,7 +383,7 @@ fn stringify(
383383

384384
第一个参数 `value: anytype` 是显而易见的,它是要序列化的值,可以是任何类型(实际上,Zig 的 JSON 序列化器不能序列化某些类型,比如 HashMap)。我们可以猜测,`out_stream` 是写入 JSON 的地方,但至于它需要实现什么方法,你和我一样猜得到。唯一的办法就是阅读源代码,或者传递一个假值,然后使用编译器错误作为我们的文档。如果有更好的自动文档生成器,这一点可能会得到改善。不过,我希望 Zig 能提供接口,这已经不是第一次了。
385385

386-
# [@TypeOf]($section.id('typeof'))
386+
# [@TypeOf]($heading.id('typeof'))
387387

388388
在前面的部分中,我们使用 `@TypeOf` 来帮助我们检查各种变量的类型。从我们的用法来看,你可能会认为它返回的是字符串类型的名称。然而,鉴于它是一个 PascalCase 风格函数,你应该更清楚:它返回的是一个 `type`。
389389

@@ -412,7 +412,7 @@ pub const User = struct {
412412

413413
更常见的是 `@TypeOf` 与 `@typeInfo` 配对,后者返回一个 `std.builtin.Type`。这是一个功能强大的带标签的联合(tagged union),可以完整描述一个类型。`std.json.stringify` 函数会递归地调用它,以确定如何将提供的 `value` 序列化。
414414

415-
# [构建系统]($section.id('build-system'))
415+
# [构建系统]($heading.id('build-system'))
416416

417417
如果你通读了整本指南,等待着深入了解如何建立更复杂的项目,包括多个依赖关系和各种目标,那你就要失望了。Zig 拥有强大的构建系统,以至于越来越多的非 Zig 项目都在使用它,比如 libsodium。不幸的是,所有这些强大的功能都意味着,对于简单的需求来说,它并不是最容易使用或理解的。
418418

@@ -497,7 +497,7 @@ test "dummy build test" {
497497

498498
这是启动和运行构建系统所需的最低配置。但是请放心,如果你需要构建你的程序,Zig 内置的功能大概率能覆盖你的需求。最后,你可以(也应该)在你的项目根目录下使用 `zig init`,让 Zig 为你创建一个文档齐全的 `build.zig` 文件。
499499

500-
# [第三方依赖]($section.id('third-party-dependencies'))
500+
# [第三方依赖]($heading.id('third-party-dependencies'))
501501

502502
Zig 的内置软件包管理器相对较新,因此存在一些缺陷。虽然还有改进的余地,但它目前还是可用的。我们需要了解两个部分:创建软件包和使用软件包。我们将对其进行全面介绍。
503503

content/learn/heap-memory.smd

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
本部分分为两个主题。第一个主题是第三个内存区域--堆的总体概述。另一个主题是 Zig 直接而独特的堆内存管理方法。即使你熟悉堆内存,比如使用过 C 语言的 `malloc`,你也会希望阅读第一部分,因为它是 Zig 特有的。
1616

17-
# [堆]($section.id('heap'))
17+
# [堆]($heading.id('heap'))
1818

1919
堆是我们可以使用的第三个也是最后一个内存区域。与全局数据和调用栈相比,堆有点像蛮荒之地:什么都可以使用。具体来说,在堆中,我们可以在运行时创建大小已知的内存,并完全控制其生命周期。
2020

@@ -52,7 +52,7 @@ fn getRandomCount() !u8 {
5252

5353
一般来说,每次 `alloc` 都会有相应的 `free`。`alloc`分配内存,`free`释放内存。不要让这段简单的代码限制了你的想象力。这种 `try alloc` + `defer free` 的模式很常见,这是有原因的:在我们分配内存的地方附近释放相对来说是万无一失的。但同样常见的是在一个地方分配,而在另一个地方释放。正如我们之前所说,堆没有内置的生命周期管理。你可以在 HTTP 处理程序中分配内存,然后在后台线程中释放,这是代码中两个完全独立的部分。
5454

55-
# [defer 和 errdefer]($section.id('defer-and-errdefer'))
55+
# [defer 和 errdefer]($heading.id('defer-and-errdefer'))
5656

5757
说句题外话,上面的代码介绍了一个新的语言特性:`defer`,它在退出作用域时执行给定的代码。『作用域退出』包括到达作用域的结尾或从作用域返回。严格来说, `defer` 与分配器或内存管理并无严格关系;你可以用它来执行任何代码。但上述用法很常见。
5858

@@ -100,7 +100,7 @@ pub const Game = struct {
100100

101101
> `init` 和 `deinit` 的名字并不特殊。它们只是 Zig 标准库使用的,也是社区采纳的名称。在某些情况下,包括在标准库中,会使用 `open` 和 `close`,或其他更适当的名称。
102102

103-
# [双重释放和内存泄漏]($section.id('double-free-and-memory-leak'))
103+
# [双重释放和内存泄漏]($heading.id('double-free-and-memory-leak'))
104104

105105
上面提到过,没有规则规定什么时候必须释放什么东西。但事实并非如此,还是有一些重要规则,只是它们不是强制的,需要你自己格外小心。
106106

@@ -159,7 +159,7 @@ fn isSpecial(allocator: Allocator, name: [] const u8) !bool {
159159

160160
至少在双重释放的情况下,我们的程序会遭遇严重崩溃。内存泄漏可能很隐蔽。不仅仅是根本原因难以确定。真正的小泄漏或不常执行的代码中的泄漏甚至很难被发现。这是一个很常见的问题,Zig 提供了帮助,我们将在讨论分配器时看到。
161161

162-
# [创建与销毁]($section.id('create-and-destroy'))
162+
# [创建与销毁]($heading.id('create-and-destroy'))
163163

164164
`std.mem.Allocator`的`alloc`方法会返回一个切片,其长度为传递的第二个参数。如果想要单个值,可以使用 `create` 和 `destroy` 而不是 `alloc` 和 `free`。
165165

@@ -233,7 +233,7 @@ fn init(allocator: std.mem.Allocator, id: u64, power: i32) !*User{
233233

234234
请记住,`create` 返回一个 `!*User`,所以我们的 `user` 是 `*User` 类型。
235235

236-
# [分配器 Allocator]($section.id('allocator'))
236+
# [分配器 Allocator]($heading.id('allocator'))
237237

238238
Zig 的核心原则之一是无隐藏内存分配。根据你的背景,这听起来可能并不特别。但这与 C 语言中使用标准库的 malloc 函数分配内存的做法形成了鲜明的对比。在 C 语言中,如果你想知道一个函数是否分配内存,你需要阅读源代码并查找对 malloc 的调用。
239239

@@ -254,7 +254,7 @@ defer allocator.free(say);
254254

255255
如果你正在构建一个库,那么最好接受一个 `std.mem.Allocator`,然后让库的用户决定使用哪种分配器实现。否则,你就需要选择正确的分配器,正如我们将看到的,这些分配器并不相互排斥。在你的程序中创建不同的分配器可能有很好的理由。
256256

257-
# [通用分配器 GeneralPurposeAllocator]($section.id('general-purpose-allocator'))
257+
# [通用分配器 GeneralPurposeAllocator]($heading.id('general-purpose-allocator'))
258258

259259
顾名思义,`std.heap.GeneralPurposeAllocator` 是一种通用的、线程安全的分配器,可以作为应用程序的主分配器。对于许多程序来说,这是唯一需要的分配器。程序启动时,会创建一个分配器并传递给需要它的函数。我的 HTTP 服务器库中的示例代码就是一个很好的例子:
260260

@@ -299,7 +299,7 @@ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
299299

300300
类型是什么,字段在哪里?类型其实是 `std.heap.general_purpose_allocator.Config`,但它并没有直接暴露出来,这也是我们没有显式给出类型的原因之一。没有设置字段是因为 Config 结构定义了默认值,我们将使用默认值。这是配置、选项的中常见的模式。事实上,我们在下面几行向 `init` 传递 `.{.port = 5882}` 时又看到了这种情况。在本例中,除了端口这一个字段外,我们都使用了默认值。
301301

302-
# [std.testing.allocator]($section.id('std-testing-allocator'))
302+
# [std.testing.allocator]($heading.id('std-testing-allocator'))
303303

304304
希望当我们谈到内存泄漏时,你已经足够烦恼,而当我提到 Zig 可以提供帮助时,你肯定渴望了解更多这方面内容。这种帮助来自 `std.testing.allocator`,它是一个 `std.mem.Allocator` 实现。目前,它基于通用分配器(GeneralPurposeAllocator)实现,并与 Zig 的测试运行器进行了集成,但这只是实现细节。重要的是,如果我们在测试中使用 `std.testing.allocator`,就能捕捉到大部分内存泄漏。
305305

@@ -423,7 +423,7 @@ self.allocator.free(self.items);
423423

424424
将`items`复制到我们的 `larger` 切片中后, 添加最后一行`free`可以解决泄漏的问题。如果运行 `zig test learning.zig`,便不会再有错误。
425425

426-
# [ArenaAllocator]($section.id('arena-allocator'))
426+
# [ArenaAllocator]($heading.id('arena-allocator'))
427427

428428
通用分配器(GeneralPurposeAllocator)是一个合理的默认设置,因为它在所有可能的情况下都能很好地工作。但在程序中,你可能会遇到一些固定场景,使用更专业的分配器可能会更合适。其中一个例子就是需要在处理完成后丢弃的短期状态。解析器(Parser)通常就有这样的需求。一个 `parse` 函数的基本轮廓可能是这样的
429429

@@ -508,7 +508,7 @@ defer list.deinit();
508508

509509
最后举个简单的例子,我上面提到的 HTTP 服务器在响应中暴露了一个 `ArenaAllocator`。一旦发送了响应,它就会被清空。由于`ArenaAllocator`的生命周期可以预测(从请求开始到请求结束),因此它是一种高效的选择。就性能和易用性而言,它都是高效的。
510510

511-
# [固定缓冲区分配器 FixedBufferAllocator]($section.id('fixed-buffer-allocator'))
511+
# [固定缓冲区分配器 FixedBufferAllocator]($heading.id('fixed-buffer-allocator'))
512512

513513
我们要讨论的最后一个分配器是 `std.heap.FixedBufferAllocator`,它可以从我们提供的缓冲区(即 `[]u8`)中分配内存。这种分配器有两大好处。首先,由于所有可能使用的内存都是预先创建的,因此速度很快。其次,它自然而然地限制了可分配内存的数量。这一硬性限制也可以看作是一个缺点。另一个缺点是,`free` 和 `destroy` 只对最后分配/创建的项目有效(想想堆栈)。调用释放非最后分配的内存是安全的,但不会有任何作用。
514514

content/learn/index.smd

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
.draft = false,
1212
---
1313

14-
# [《学习 Zig》 目录]($section.id('table-of-contents'))
14+
# [《学习 Zig》 目录]($heading.id('table-of-contents'))
1515

1616
- [前言](./preface)
1717
- [安装 Zig](./installing-zig)
@@ -29,7 +29,7 @@
2929

3030
初次接触 Zig 的用户可以按序号依次阅读,对于有经验的 Zig 开发者可按需阅读感兴趣的章节。
3131

32-
# [关于原作者]($section.id('about-original-author'))
32+
# [关于原作者]($heading.id('about-original-author'))
3333

3434
[Karl Seguin](https://www.linkedin.com/in/karlseguin/) 在多个领域有着丰富经验,前微软 MVP,他撰写了大量文章,是多个微软公共新闻组的活跃成员。现居新加坡。他还是以下教程的作者:
3535

@@ -39,17 +39,17 @@
3939

4040
可以在 <http://openmymind.net> 找到他的博客,或者通过 [@karlseguin](http://twitter.com/karlseguin) 在 Twitter 上关注他。
4141

42-
# [翻译原则]($section.id('translation-principles'))
42+
# [翻译原则]($heading.id('translation-principles'))
4343

4444
技术文档的翻译首要原则是准确,但在准确的前提下如何保证『信、达、雅』?这是个挑战,在翻译本教程时,在某些情况下会根据上下文进行意译,便于中文读者阅读。
4545

4646
最后,感谢翻译者的无私贡献。❤️️
4747

48-
# [离线阅读]($section.id('offline-reading'))
48+
# [离线阅读]($heading.id('offline-reading'))
4949

5050
在本仓库的 [release 页面](https://github.com/zigcc/zigcc.github.io/releases)会定期将本教程导出为 PDF 格式,读者可按需下载。
5151

52-
# [其他学习资料]($section.id('other-learning-resources'))
52+
# [其他学习资料]($heading.id('other-learning-resources'))
5353

5454
由于 Zig 目前还处于快速迭代,因此最权威的资料无疑是官方的 [Zig Language Reference](https://ziglang.org/documentation/master/),遇到语言的细节问题,基本都可以在这里找到答案。其次是社区的一些高质量教程,例如:
5555

content/learn/language-overview-1.smd

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ pub const User = struct {
3737

3838
> 请参阅[安装 Zig 部分](installing-zig),以便快速启动并运行它。
3939

40-
# [模块引用]($section.id('module-reference'))
40+
# [模块引用]($heading.id('module-reference'))
4141

4242
很少有程序是在没有标准库或外部库的情况下以单个文件编写的。我们的第一个程序也不例外,它使用 Zig 的标准库来进行打印输出。 Zig 的模块系统非常简单,只依赖于 `@import` 函数和 `pub` 关键字(使代码可以在当前文件外部访问)。
4343

@@ -88,7 +88,7 @@ const MAX_POWER = user.MAX_POWER;
8888
- 如何导入其他文件
8989
- 如何导出变量、函数定义
9090

91-
# [代码注释]($section.id('code-comment'))
91+
# [代码注释]($heading.id('code-comment'))
9292

9393
下面这行 Zig 代码是一个注释:
9494

@@ -100,7 +100,7 @@ Zig 没有像 C 语言中类似 `/* ... */` 的多行注释。
100100

101101
基于注释的文档自动生成功能正在试验中。如果你看过 Zig 的标准库文档,你就会看到它的实际应用。`//!` 被称为顶级文档注释,可以放在文件的顶部。三斜线注释 (`///`) 被称为文档注释,可以放在特定位置,如声明之前。如果在错误的地方使用这两种文档注释,编译器都会出错。
102102

103-
# [函数]($section.id('function'))
103+
# [函数]($heading.id('function'))
104104

105105
下面这行 Zig 代码是程序的入口函数 `main`:
106106

@@ -146,7 +146,7 @@ fn add(a: i64, b: i64) i64 {
146146

147147
为了提高可读性,Zig 中不支持函数重载(用不同的参数类型或参数个数定义的同名函数)。暂时来说,以上就是我们需要了解的有关函数的全部内容。
148148

149-
# [结构体]($section.id('struct'))
149+
# [结构体]($heading.id('struct'))
150150

151151
下面这行代码创建了一个 `User` 结构体:
152152

@@ -266,7 +266,7 @@ pub fn init(name: []const u8, power: u64) User {
266266

267267
就像我们迄今为止已经探索过的大多数东西一样,今后在讨论 Zig 语言的其他部分时,我们会再次讨论结构体。不过,在大多数情况下,它们都是简单明了的。
268268

269-
# [数组和切片]($section.id('array-slice'))
269+
# [数组和切片]($heading.id('array-slice'))
270270

271271
我们可以略过代码的最后一行,但鉴于我们的代码片段包含两个字符串 `"Goku"` 和 `{s}'s power is {d}\n`,你可能会对 Zig 中的字符串感到好奇。为了更好地理解字符串,我们先来了解一下数组和切片。
272272

@@ -365,7 +365,7 @@ pub fn main() void {
365365

366366
在了解 Zig 语言的其他方面(尤其是字符串)的同时,我们还将发现更多有关数组和切片的知识。
367367

368-
# [字符串]($section.id('string'))
368+
# [字符串]($heading.id('string'))
369369

370370
我希望我能说,Zig 里有字符串类型,而且非常棒。遗憾的是,它没有。最简单来说,字符串是字节(u8)的序列(即数组或切片)。实际上,我们可以从 `name` 字段的定义中看到这一点:`name: []const u8`.
371371

@@ -399,7 +399,7 @@ pub fn main() void {
399399

400400
当然,在实际程序中,大多数字符串(以及更通用的数组)在编译时都是未知的。最典型的例子就是用户输入,程序编译时并不知道用户输入。这一点我们将在讨论内存时再次讨论。但简而言之,对于这种在编译时不能确定值的数据(长度当然也就无从得知),我们将在运行时动态分配内存。我们的字符串变量(仍然是 `[]const u8` 类型)将是指向动态分配的内存的切片。
401401

402-
# [comptime 和 anytype]($section.id('comptime-and-anytype'))
402+
# [comptime 和 anytype]($heading.id('comptime-and-anytype'))
403403

404404
在我们未解释的最后一行代码中,涉及的知识远比表面看到的多:
405405

0 commit comments

Comments
 (0)