Skip to content

Commit 79cf5c8

Browse files
committed
feat: 🎸 完善第9章宏
1 parent 353beb5 commit 79cf5c8

9 files changed

Lines changed: 954 additions & 179 deletions

File tree

.vitepress/nav.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ export default [
4343
{ text: "Comprehensive Rust 🦀", link: "https://google.github.io/comprehensive-rust/" },
4444
{ text: "Rust 设计模式", link: "https://github.com/Fomalhauthmj/patterns/" },
4545
{ text: "Rust Primer", link: "https://rustcc.gitbooks.io/rustprimer" },
46-
{ text: "Rust 宏小册", link: "https://zjp-cn.github.io/tlborm/" },
4746
{ text: "Rust 语言圣经", link: "https://course.rs/" },
4847
{ text: "Rusty Book", link: "https://rusty.course.rs/" },
4948
{ text: "Rust By Practice", link: "https://zh.practice.rs/why-exercise.html" },

docs/第 11 章 所有权和移动语义/11.5 Clone VS Copy.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@ Rust 中的 Copy 是一个特殊的 trait,它给类型提供了“复制”语
77
Copy 的全名是`std::marker::Copy`
88
请大家注意,`std::marker` 模块里面所有的 trait 都是特殊的 trait。目前稳定的有四个,它们是 `Copy``Send``Sized``Sync`。它们的特殊之处在于:它们是跟编译器密切绑定的,impl 这些 trait 对编译器的行为有重要影响。在编译器眼里,它们与其他的 trait 不一样。这几个 trait 内部都没有方法,它们的唯一任务是给类型打一个“标记”,表明它符合某种约定——这些约定会影响编译器的静态检查以及代码生成。
99

10-
Copy 这个 trait 在编译器的眼里代表的是什么意思呢?简单点总结就是,如果一个类型 impl 了 Copy trait,意味着任何时候,我们都可以通过简单的内存复制(在 C 语言里按字节复制 memcpy)实现该类型的复制,并且不会产生任何内存安全问题。
10+
Copy 这个 trait 在编译器的眼里代表的是什么意思呢?简单点总结就是,如果一个类型 impl 了 Copy trait,意味着任何时候,我们都可以通过简单的内存复制(在 C 语言里按字节复制 `memcpy`)实现该类型的复制,并且不会产生任何内存安全问题。
1111

12-
一旦一个类型实现了`Copy trait`,那么它在变量绑定、函数参数传递、函数返回值传递等场景下,都是 copy 语义,而不再是默认的 move 语义。
12+
==一旦一个类型实现了`Copy trait`,那么它在变量绑定、函数参数传递、函数返回值传递等场景下,都是 copy 语义,而不再是默认的 move 语义==
1313

14-
下面用最简单的赋值语句`x = y`来说明 move 语义和 copy 语义的根本区别。move 语义是“剪切、粘贴”操作,变量 y 把所有权递交给了 x 之后,y 就彻底失效了,后面继续使用 y 就会出编译错误。而 copy 语义是“复制、粘贴”操作,变量 y 把所有权递交给了 x 之后,它自己还留了一个副本,在这句赋值语句之后,xy 依然都可以继续使用。
14+
下面用最简单的赋值语句`x = y`来说明 move 语义和 copy 语义的根本区别。move 语义是“剪切、粘贴”操作,变量 `y` 把所有权递交给了 `x` 之后,`y` 就彻底失效了,后面继续使用 `y` 就会出编译错误。而 copy 语义是“复制、粘贴”操作,变量 `y` 把所有权递交给了 `x` 之后,它自己还留了一个副本,在这句赋值语句之后,`x``y` 依然都可以继续使用。
1515

16-
在 Rust 里,move 语义和 copy 语义具体执行的操作,是不允许由程序员自定义的,这是它和 C++的巨大区别。这里没有赋值构造函数或者赋值运算符重载。move 语义或者 copy 语义都是执行的 memcpy,无法更改,这个过程中绝对不存在其他副作用。当然,这里一直谈的是“语义”,而没有涉及编译器优化。从语义的角度,我们要讲清楚,什么样的代码在编译器看来是合法的,什么样的代码是非法的。如果考虑后端优化,在许多情况下,不必要的内存复制实际上已经彻底优化掉了,大家不必担心执行效率的问题。也没有必要每次都把 move 或者 copy 操作与具体的汇编代码联系起来,因为场景不同,优化结果不同,生成的代码也是不同的。大家只需记住的是语义。
16+
在 Rust 里,move 语义和 copy 语义具体执行的操作,是不允许由程序员自定义的,这是它和 C++的巨大区别。这里没有赋值构造函数或者赋值运算符重载。move 语义或者 copy 语义都是执行的 `memcpy`,无法更改,这个过程中绝对不存在其他副作用。当然,这里一直谈的是“语义”,而没有涉及编译器优化。从语义的角度,我们要讲清楚,什么样的代码在编译器看来是合法的,什么样的代码是非法的。如果考虑后端优化,在许多情况下,不必要的内存复制实际上已经彻底优化掉了,大家不必担心执行效率的问题。也没有必要每次都把 move 或者 copy 操作与具体的汇编代码联系起来,因为场景不同,优化结果不同,生成的代码也是不同的。大家只需记住的是语义。
1717

1818
## 11.5.2 Copy 的实现条件
1919

docs/第 32 章 项目和模块(第五部分 实用设施)/32.3 模块管理.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,3 +332,33 @@ fn call() {
332332
use std::result::Result as StdResult;
333333
use std::io::Result as IoResult;
334334
```
335+
336+
## 包名问题
337+
338+
在 rust 中 Cargo 包名(crate name)是允许使用连字符 `-`的,而 Rust 标识符(identifier)不允许使用连字符,只能使用下划线 `_`。所以在代码中引用包名时,如:
339+
340+
```rust
341+
use my-lib::funx;
342+
```
343+
344+
需要改为:
345+
```rust
346+
use my_lib::funx;
347+
```
348+
349+
Rust 会自动将包名中的连字符转换为下划线。
350+
351+
352+
如果你想在代码中使用不同的名称,可以在 Cargo.toml 中重命名依赖:
353+
354+
```toml
355+
[dependencies]
356+
my_lib = { path = "my-alib", package = "my-alib" }
357+
```
358+
359+
然后在代码中使用:
360+
```rust
361+
use my_lib::funx;
362+
```
363+
364+
这样就可以正常编译了。

docs/第 9 章 宏/9.1 简介 macro.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
宏也可以通过`some_macro![...]``some_macro!{ ... }`两种语法调用,只要括号能正确匹配即可。
66
我们在本书一开始就已经使用了“宏”,大家一定记得`println!`这个宏,它可以用于向标准输出打印字符串。
77

8-
与 C/C++ 中的宏不一样的是,Rust 中的宏是一种比较安全的“卫生宏”(hygiene)。
8+
与 C/C++ 中的宏不一样的是,Rust 中的宏是一种比较安全的“卫生宏”(Hygiene)。
99
首先,Rust 的宏在调用的时候跟函数有明显的语法区别;其次,宏的内部实现和外部调用者处于不同名字空间,它的访问范围严格受限,是通过参数传递进去的,我们不能随意在宏内访问和改变外部的代码。
10-
C/C++中的宏只在预处理阶段起作用,因此只能实现类似文本替换的功能。
10+
C/C++ 中的宏只在预处理阶段起作用,因此只能实现类似文本替换的功能。
1111
而 Rust 中的宏在语法解析之后起作用,因此可以获取更多的上下文信息,而且更加安全。
1212

1313
我们可以把“宏”视为“元编程”的一种方式。它是一种“生成程序的程序”。宏有很多用处。

0 commit comments

Comments
 (0)