Skip to content

Commit 666589f

Browse files
committed
docs: 改进文档表述以提高可读性和准确性
将技术概念的定义更新为更清晰的表述,便于读者理解原理而非仅记住术语。原子操作顺序级别、编译期求值、泛型参数多态、反射等概念均补充了背景说明。修正术语和链接错误。
1 parent 1e5bb4e commit 666589f

File tree

23 files changed

+82
-68
lines changed

23 files changed

+82
-68
lines changed

course/advanced/atomic.md

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,16 @@ outline: deep
1515

1616
在讲述下列的内建函数前,我们需要了解一下前置知识:
1717

18-
**原子操作的顺序级别**:为了实现性能和必要保证之间的平衡,原子性分为六个级别。它们按照强度顺序排列,每个级别都包含上一个级别的所有保证。
18+
**原子操作的顺序级别(Memory Ordering)**:为了实现性能和必要保证之间的平衡,原子操作提供了不同的内存排序级别。它们按照约束强度从弱到强排列:
1919

20-
关于原子顺序六个级别的具体说明,见 [LLVM](https://llvm.org/docs/Atomics.html#atomic-orderings)
20+
- **Unordered**:最弱的原子保证。仅保证操作本身是原子的(不会被撕裂),但不提供任何跨线程的顺序保证。
21+
- **Monotonic**(对应 C++ 的 `memory_order_relaxed`):保证同一线程内对同一变量的原子操作是单调有序的,但不阻止不同变量之间的操作重排序。适用于简单的计数器等场景。
22+
- **Acquire**:读操作使用。保证当前线程在此读操作**之后**的所有读写操作,不会被重排到此操作之前。常用于获取锁。
23+
- **Release**:写操作使用。保证当前线程在此写操作**之前**的所有读写操作,不会被重排到此操作之后。常用于释放锁。
24+
- **AcqRel**(Acquire + Release):同时具备 Acquire 和 Release 语义,适用于读-改-写(Read-Modify-Write)操作。
25+
- **SeqCst**(Sequentially Consistent):最强的保证。除了包含 AcqRel 的所有保证外,还保证所有线程观察到的 SeqCst 操作的顺序是一致的。开销最大,但最易于推理。
2126

22-
<!-- **NotAtomic**
23-
24-
简单的非原子加载或者存储,即常规加载或存储。
25-
26-
**Unordered**
27-
28-
无序的原子级别,是最低级别。意味着一组操作可以以任意的顺序原子执行,只需要结果而不管过程以何种顺序执行。
29-
30-
**Monotonic**
31-
32-
保证原子操作是单调的,在一个线程中,所观察到的原子值在后续过程中必定是大于或等于当前值。但在多线程中,并不保证不会发生重排序 -->
27+
关于更多细节,见 [LLVM Atomics](https://llvm.org/docs/Atomics.html#atomic-orderings)
3328

3429
### [`@atomicLoad`](https://ziglang.org/documentation/master/#atomicLoad)
3530

course/advanced/comptime.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@ outline: deep
66

77
在开始之前,我们需要先梳理一下,什么是**编译期**
88

9-
对于这个概念,你可能会一脸懵逼。所以我们先看一下什么是运行时(runtime)
9+
要理解编译期,我们先回顾一下**运行时(Runtime)**的概念
1010

11-
> 在计算机科学中代表一个计算机程序从开始执行到终止执行的运作、执行的时期。”
11+
> 在计算机科学中,运行时代表一个计算机程序从开始执行到终止执行的运作、执行的时期。”
1212
13-
对应地,我们可以尝试给编译期做一个定义:“zig 编译期是指在 zig 编译期间执行的动作。”
13+
对应地,**编译期求值(Compile-time Evaluation)** 是指在编译阶段——即源代码被翻译为机器码的过程中——对表达式进行求值的机制。与运行时求值不同,编译期求值的结果会被直接嵌入到最终的二进制产物中,不产生任何运行时开销。
1414

1515
:::info 🅿️ 提示
1616

@@ -25,9 +25,11 @@ outline: deep
2525
- 在这个调用点,标记的值必须是在编译期已知的,否则 zig 会报告错误!
2626
- 在函数定义中,该值(包括参数、类型)必须是编译期已知的(但无需全部都是编译期已知的,仅保证依赖关系中的符合即可)!
2727

28-
## 编译期参数实现鸭子类型
28+
## 编译期参数实现泛型(参数多态)
2929

30-
> “当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。”
30+
> "当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那么这只鸟就可以被称为鸭子。"
31+
32+
上面这句话描述的是动态语言中的"鸭子类型"。Zig 的编译期泛型与之类似但有本质区别:Zig 是在**编译期**通过参数多态(Parametric Polymorphism)来实现泛型的——类型作为编译期参数传入,编译器会为每个具体类型生成特化的代码,所有类型检查都在编译期完成。
3133

3234
一个实现 `max` 功能的函数:
3335

course/advanced/interact-with-c.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ pub const MAKELOCAL =
176176

177177
应尽量避免使用此类型,通常它仅出现在翻译输出代码中。
178178

179-
导入 C 头文件后,zig 并不知道如何处理指针(因为 C 的指针可以同时作为单项指针和多项指针使用),这会导致歧义,故 zig 引入一种新类型 `[*c]T`,作为一种折中方案,新类型 `[*c]T` 具有以下特点:
179+
导入 C 头文件后,Zig 并不知道如何处理指针(因为 C 的指针可以同时作为单项指针和多项指针使用),这会导致歧义。为此,Zig 引入了 `[*c]T` 类型作为**兼容性退化机制**——它在类型信息不完整时保持与 C 的互操作性,同时允许开发者后续将其转换为更精确的 Zig 指针类型。`[*c]T` 具有以下特点:
180180

181181
1. 支持 zig 普通指针(`*T` 和 `[*]T`)的全部语法。
182182
2. 可以强制转换为其他的任意指针类型,当然也包括可选指针类型(当被转换为非可选指针时,如果地址为 0,此时会触发安全检查的保护机制,报错并通知出现了未定义行为)。

course/advanced/memory_manage.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ outline: deep
1818
6. [`page_allocator`](https://ziglang.org/documentation/master/std/#std.heap.page_allocator)
1919
7. [`StackFallbackAllocator`](https://ziglang.org/documentation/master/std/#std.heap.StackFallbackAllocator)
2020

21-
除了这八种内存分配模型外,还提供了内存池的功能 [`MemoryPool`](https://ziglang.org/documentation/master/std/#std.heap.memory_pool.MemoryPool)
21+
除了这七种内存分配模型外,还提供了内存池的功能 [`MemoryPool`](https://ziglang.org/documentation/master/std/#std.heap.memory_pool.MemoryPool)
2222

2323
你可能对上面的多种内存模型感到很迷惑,C 语言中不就是 `malloc` 吗,怎么到这里这么多的“模型”,这些模型均有着不同的特点,而且它们之间有一部分还可以叠加使用,Zig 在这方面提供了更多的选择,而且不仅仅是这些,你还可以自己尝试实现一个内存模型。
2424

course/advanced/reflection.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ outline: deep
44

55
# 反射
66

7-
> 在计算机学中,反射(**reflection**,是指计算机程序在运行时(**runtime**)可以访问、检测和修改它本身状态或行为的一种能力。用比喻来说,反射就是程序在运行的时候能够“观察”并且修改自己的行为
7+
> 在计算机科学中,反射(**Reflection**是指程序在执行过程中可以访问、检测和修改自身结构或行为的一种能力
88
9-
事实上,由于 zig 是一门强类型的静态语言,因此它的反射是在编译期实现的,允许我们观察已有的类型,并根据已有类型的信息来创造新的类型!
9+
反射通常包含两个层面:**内省(Introspection)**——即程序检查自身类型信息的能力;以及**中间表示操纵(Intercession)**——即程序修改自身结构的能力。
10+
11+
在传统的动态语言(如 Python、Ruby)中,反射发生在运行时。而 Zig 是一门强类型的静态语言,它的反射完全在**编译期**实现——我们可以在编译期观察已有类型的信息(内省),并根据这些信息构建全新的类型(有限度的中间表示操纵)。这种编译期反射的优势在于:不会引入任何运行时开销,且所有类型错误都能在编译期被捕获。
1012

1113
## 观察已有类型
1214

course/advanced/type_cast.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ undefined 是一个神奇的值,它可以赋值给所有类型,代表这个
126126

127127
## 对等类型转换
128128

129-
对等类型转换(**Peer Type Resolution**,这个词汇仅仅在 zig 的文档中出现过,它看起来与前面提到的普通类型解析很像,根据 zig[开发手册](https://ziglang.org/documentation/master/)所述,它发生在以下情况:
129+
对等类型转换(**Peer Type Resolution**是 Zig 类型系统中的一种类型推断机制。其核心思想是:当多个表达式需要产生统一类型的结果时,编译器会自动寻找它们的**最小公共超类型(Least Upper Bound)**——即能够无损表示所有参与类型的最小类型。根据 Zig[开发手册](https://ziglang.org/documentation/master/)所述,它发生在以下情况:
130130

131131
- `switch` 的表达式
132132
- `if` 的表达式

course/basic/advanced_type/pointer.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ Zig 支持指针的加减运算,但建议在进行运算前,将指针转换
116116

117117
:::
118118

119-
## 多项指针和单向指针区别
119+
## 多项指针和单项指针区别
120120

121121
本节专门解释单项指针和多项指针的区别。
122122

course/basic/advanced_type/slice.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ slice_2 类型为[]i32
3232

3333
在上面的例子中,我们从一个数组创建切片,其左边界为 0,右边界为变量 `len`
3434

35-
注意:如果切片的两个边界值都是编译期常量,编译器会将其优化为数组指针;但如果至少有一个边界值是运行时变量,那么它就是一个真正的切片
35+
注意:如果切片的两个边界值都是编译期常量,编译器在类型推断时会将结果推断为数组指针类型(因为长度在编译期已知);但如果至少有一个边界值是运行时变量,那么结果类型就是切片(长度在运行时确定)
3636

3737
:::info 🅿️ 提示
3838

course/basic/advanced_type/string.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ Unicode 码点字面量类型是 `comptime_int`。所有转义字符都可以在
5050
:::info
5151

5252
字符串字面量中不能直接包含`<Tab>`字符(Zig 语言规范不允许在源代码中使用`<Tab>`)。但可以使用`\t`转义序列或`@embedFile`内建函数来实现类似的功能。
53-
参考:[enum-backed address spaces](https://github.com/ziglang/zig-spec/issues/38]
53+
参考:[enum-backed address spaces](https://github.com/ziglang/zig-spec/issues/38)
5454

5555
:::
5656

course/basic/advanced_type/struct.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137

138138
然而,仅此还不够。在实际使用中,我们可能只初始化部分字段,而其他字段使用默认值。如果对结构体字段的默认值没有不变性要求,那么这种默认值方案已经足够使用。
139139

140-
但如果要求结构体字段的值具有默认不变性(即要么全部使用默认值,要么全部由使用者手动赋值),则可以采用以下方案:
140+
但如果需要"全有或全无"(All-or-Nothing)的初始化策略——即要么全部使用默认值,要么全部由使用者手动赋值——则可以采用以下方案:
141141

142142
<<<@/code/release/struct.zig#all_default
143143

0 commit comments

Comments
 (0)