Skip to content

Commit 9b55621

Browse files
xihalexihalejinzhongjia
authored
Chore changes (#212)
* chore changes * 关于tab无法使用于多行字符串对应的版本说明 --------- Co-authored-by: xihale <[email protected]> Co-authored-by: jinzhongjia <[email protected]>
1 parent f5428ba commit 9b55621

File tree

8 files changed

+58
-22
lines changed

8 files changed

+58
-22
lines changed

course/basic/advanced_type/array.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,16 @@ outline: deep
3232

3333
在以上的示例中,我们使用了 [for](/basic/process_control/loop) 循环,来进行矩阵的打印,关于循环我们放在后面再聊。
3434

35-
## 哨兵数组
35+
## 哨兵数组(标记终止数组)
3636

3737
> 很抱歉,这里的名字是根据官方的文档直接翻译过来的,原文档应该是 ([Sentinel-Terminated Arrays](https://ziglang.org/documentation/master/#toc-Sentinel-Terminated-Arrays)) 。
3838
39+
:::info
40+
41+
本质上来说,这是为了兼容 C 中的规定的字符串结尾字符`\0`
42+
43+
:::
44+
3945
我们使用语法 `[N:x]T` 来描述一个元素为类型 `T`,长度为 `N` 的数组,在它对应 `N` 的索引处的值应该是 `x`。前面的说法可能比较复杂,换种说法,就是这个语法表示数组的长度索引处的元素应该是 `x`,具体可以看下面的示例:
4046

4147
<<<@/code/release/array.zig#terminated_array
@@ -48,6 +54,12 @@ outline: deep
4854

4955
## 操作
5056

57+
:::info
58+
59+
以下操作都是编译期 (comptime) 的,如果你需要运行时地处理数组操作,请使用 `std.mem`
60+
61+
:::
62+
5163
### 乘法
5264

5365
可以使用 `**` 对数组做乘法操作,运算符左侧是数组,右侧是倍数,进行矩阵的叠加。

course/basic/advanced_type/pointer.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,13 @@ zig 本身支持指针运算(加减操作),但有一点需要注意:最
7272

7373
:::
7474

75-
### 哨兵指针
75+
### 哨兵指针(标记终止指针)
76+
77+
:::info
78+
79+
本质上来说,这是为了兼容 C 中的规定的字符串结尾字符`\0`
80+
81+
:::
7682

7783
哨兵指针就和哨兵数组类似,我们使用语法 `[*:x]T`,这个指针标记了边界的值,故称为“哨兵”。
7884

@@ -126,11 +132,11 @@ zig 本身支持指针运算(加减操作),但有一点需要注意:最
126132
127133
对指针的操作应假定为没有副作用。如果存在副作用,例如使用内存映射输入输出(Memory Mapped Input/Output),则需要使用 `volatile` 关键字来修饰。
128134

129-
在以下代码中,保证使用 `mmio_ptr` 的值进行操作(这里你看起来可能会感到迷惑,在编译代码时,编译器可以能会让值在实际运行过程中进行缓存,这里保证每次都使用 `mmio_ptr` 的值,以避免无法正确触发“副作用”),并保证了代码执行的顺序。
135+
在以下代码中,保证使用 `mmio_ptr` 的值进行操作(这里你看起来可能会感到迷惑,在编译代码时,编译器可以能会让值在实际运行过程中进行缓存,这里保证每次都使用 `mmio_ptr` 的值,以确保正确触发“副作用”),并保证了代码执行的顺序。
130136

131137
<<<@/code/release/pointer.zig#volatile
132138

133-
该节内容,仅仅讲述的少量内容,如果要了解更多,你可能需要查看[官方文档](https://ziglang.org/documentation/master/#toc-volatile)
139+
该节内容,此处仅仅讲述了少量内容,如果要了解更多,你可能需要查看[官方文档](https://ziglang.org/documentation/master/#toc-volatile)
134140

135141
### 对齐
136142

@@ -139,6 +145,12 @@ zig 本身支持指针运算(加减操作),但有一点需要注意:最
139145
每种类型都有一个对齐方式——数个字节,这样,当从内存加载或存储该类型的值时,内存地址必须能被该数字整除。我们可以使用 `@alignOf` 找出任何类型的内存对齐大小。
140146

141147
内存对齐大小取决于 CPU 架构,但始终是 2 的幂,并且小于 1 << 29。
148+
:::info
149+
150+
`align(0)` 表意是:无需对齐,这在高性能、内存紧迫场景下用处很大。
151+
参考:[allow align(0) on struct fields](https://github.com/ziglang/zig/issues/3802)
152+
153+
:::
142154

143155
在 Zig 中,指针类型具有对齐值。如果该值等于基础类型的对齐方式,则可以从类型中省略它:
144156

course/basic/advanced_type/slice.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ slice.ptr 类型为[*]i32
6666
slice 的索引 0 取地址,得到指针类型为*i32
6767
```
6868

69-
## 哨兵切片
69+
## 哨兵切片(标记终止切片)
7070

7171
语法 `[:x]T` 是一个切片,它具有运行时已知的长度,并且还保证由该长度索引的元素的标记值。该类型不保证在此之前不存在哨兵元素,哨兵终止的切片允许元素访问 len 索引。
7272

course/basic/advanced_type/string.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ Unicode 码点字面量类型是 `comptime_int`,所有的转义字符均可以
5353

5454
如果要使用多行字符串,可以使用 `\\`,多行字符串没有转义,最后一行行尾的换行符号不会包含在字符串中。示例如下:
5555

56+
:::info
57+
58+
`0.14.0` 开始,字符串中不能出现`<Tab>`(在 Zig 中任何`<Tab>`都是不被允许的),但是可以用`\t`或者`@embedFile`实现平行功能。
59+
参考:[enum-backed address spaces](https://github.com/ziglang/zig-spec/issues/38)
60+
61+
:::
62+
5663
<<<@/code/release/string.zig#multiline_string
5764

5865
### 常见错误

course/basic/advanced_type/struct.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ zig 在使用结构体的时候还支持省略结构体类型,只要能让 zig
101101

102102
:::info 🅿️ 提示
103103

104-
当然这种操作不局限于声明变量,你在函数中也可以使用(当编译器无法完成推断时,它会给出一个完整的堆栈跟踪)!
104+
当然这种操作不局限于声明变量,你在函数中也可以使用(当编译器无法完成推断时,它会给出一个包含完整堆栈跟踪的报错)!
105105

106106
:::
107107

@@ -125,11 +125,12 @@ zig 在使用结构体的时候还支持省略结构体类型,只要能让 zig
125125

126126
:::info 🅿️ 提示
127127

128-
使用 Go 的朋友对这个可能很熟悉,在 Go 中经常用空结构体做实体在 chan 中传递,它的内存大小为 0!
128+
使用 Go 的朋友对这个可能很熟悉,在 Go 中经常用空结构体做实体在 chan 中传递,它的内存大小为 0!
129+
而在 C++ 中,这样的空结构体的内存大小则是 1。
129130

130131
:::
131132

132-
## 通过字段获取基指针
133+
## 通过字段获取基指针(基于字段的指针)
133134

134135
为了获得最佳的性能,结构体字段的顺序是由编译器决定的,但是,我们可以仍然可以通过结构体字段的指针来获取到基指针!
135136

course/basic/optional_type.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,23 @@ outline: deep
44

55
# 可选类型
66

7-
zig 在不损害效率和可读性的前提下提高代码安全性的一个方案就是可选类型,`?` 是可选类型的标志,你可以将它放在类型的前面,代表它的值是 null 或者这个类型。
7+
## Overview
8+
9+
在 Zig 中,要在不损害效率的前提下,尽量提高代码安全性,其中一个方案就是可选类型,他的标志是 `?``?T`表示它的值是它的值是 `null``T`
810

911
<<<@/code/release/optional_type.zig#basic_type
1012

11-
当然,可选类型在整数上没什么大用,更多是在指针上使用,null(空引用)是许多运行时异常的根源,甚至被指责为[计算机科学中最严重的错误](https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/)
13+
当然,它一般在指针上发挥作用,而不是整数。
14+
15+
`null`(空引用)是许多运行时异常的根源,甚至被指责为[计算机科学中最严重的错误](https://www.lucidchart.com/techblog/2015/08/31/the-worst-mistake-of-computer-science/)
1216

13-
当然这在 zig 中不存在,通过可选类型我们可以解决这个问题,zig 在解决空指针上采取的方式比较保守,它兼顾了代码的可读性和效率问题
17+
我们可以通过可选类型来规避它。这其实是一种比较保守的做法,它同时兼顾了代码的可读性和运行效率。目前最为激进的应该是 _Rust_,它真的是非常的激进,这增加了程序员在写代码时的心智负担(因为你经常需要和编译期斗智斗勇,但好处大大是减少了你在运行时 _Debug_ 的负担)。相对地,zig 采取了一种折中方案,编译期进行简单的检测,而且检测出来的错误一般很容易纠正;这样的缺点是并不能保证你的运行时是绝对安全的(可选类型仅仅能避免空指针问题,却不能避免悬空指针、迷途指针和野指针等问题)
1418

15-
其中目前最为激进的应该是 _Rust_,它真的是非常的激进,这增加了程序员在写代码时的心智负担(因为你经常需要和编译期斗智斗勇,但好处大大是减少了你在运行时 _Debug_ 的负担)。相对来说,zig 采取的是一种折中的方案,编译期仍然会给你检测,并且这种检测不是很深奥,而且纠正起来很简单,缺点是并不能保证你的运行时是绝对安全的(可选类型仅仅能保证你不使用空指针,却不能保证你出现悬空指针【迷途指针、野指针】等情况的出现)
19+
zig 将 `null` 特殊看待,并且保证 `null` 不会被赋值给一个非可选类型变量
1620

17-
zig 会将 `null` 特殊看待,并且保证你不会将一个可能为 `null` 的值赋值给一个不可能是 `null` 的变量。
21+
## 和 C 对比
1822

19-
首先我们和 zig 的目标:C 对比一下,看一下两者在处理 `null` 上的区别,在接下来的代码中,我们尝试调用 `malloc`,并且申请一块内存:
23+
看看下面代码中两者在处理 `null` 上的区别。(尝试调用 `malloc` 申请一块内存。)
2024

2125
::: code-group
2226

@@ -35,9 +39,9 @@ struct Foo *do_a_thing(void) {
3539
3640
:::
3741
38-
在这里,至少 zig 看起来要比 c 好用,我们通过使用 `orelse` 关键字保证解构了可选类型,保证我们这里的 `ptr` 一定是一个可用的指针,否则的话我们直接会返回 `null`。
42+
在这里,我们通过使用 `orelse` 解构了可选类型,保证 `ptr` 是一个合法可用的指针,否则直接返回 `null`。(这看起来比 C 更加明了且易用)
3943
40-
我们再来对比一下 _C_ 和 _Zig_ 处理 `null` 的方式
44+
再看下例
4145
4246
:::code-group
4347
@@ -55,9 +59,9 @@ void do_a_thing(struct Foo *foo) {
5559

5660
:::
5761

58-
看起来区别不大,zig 只是在 if 语法有点不同,这个块中保证了 `foo` 不是一个可选类型的指针,而是一个指针
62+
看起来区别不大,只是在 `if` 语法上有点不同,`if` 块中保证 `foo` 不为 `null`
5963

60-
当然在 c 中你可以使用 `__attribute__((nonnull))` 来告诉 GCC 编译器这里不能是一个 null,但使用成本明显要比 zig 高。
64+
当然,在 C 中,你可以用 `__attribute__((nonnull))` 来告诉 C 编译器这里不不可能是 `null`,但其使用成本明显比 Zig 高。
6165

6266
## 编译期反射访问可选类型
6367

@@ -68,10 +72,6 @@ void do_a_thing(struct Foo *foo) {
6872

6973
<<<@/code/release/optional_type.zig#comptime_access_optional_type
7074

71-
## `null`
72-
73-
`null` 是一个独特的类型,类似 `undefined`,它的使用方式就是赋值给可选类型!
74-
7575
## 可选指针
7676

7777
可选指针会保证和指针有一样的大小,`null` 会被视作地址 0 考虑!

course/code/12/error_handle.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ const NotHandleError = struct {
173173
} else |_| {
174174
// 你也可以在这里做点额外的事情
175175
}
176+
// 或者你也可以这样:
177+
parseU64(str, 10) catch {};
176178
}
177179
// #endregion NotHandleError
178180
};

course/code/14/error_handle.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ const NotHandleError = struct {
173173
} else |_| {
174174
// 你也可以在这里做点额外的事情
175175
}
176+
// 或者你也可以这样:
177+
parseU64(str, 10) catch {};
176178
}
177179
// #endregion NotHandleError
178180
};

0 commit comments

Comments
 (0)