Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/safe-guides/coding_practice/async-await/G.ASY.01.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

**【描述】**

在此条件下 `.await` 语句通常为必须的

**【反例】**

Expand Down
2 changes: 1 addition & 1 deletion src/safe-guides/coding_practice/async-await/G.ASY.03.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
## G.ASY.03 在跨 `await` 调用中,需要对其持有 `RefCell` 的引用进行处理

**【级别:建议】**
**【级别】** 建议

**【描述】**

Expand Down
2 changes: 1 addition & 1 deletion src/safe-guides/coding_practice/cargo/G.CAR.01.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ bin/
这样的好处有:

1. 便于单元测试。
2. 这样拆分有利于面向接口思考,让代码架构和逻辑更加清晰。
2. 有利于面向接口思考,让代码架构和逻辑更加清晰。

若编写的可执行程序比较复杂,在 `main.rs` 里需要依赖太多东西时,那就需要创建 Workspace 把 `main.rs` 独立为一个 crate,而在这个 crate 内也没有必要再拆分为 `main` 和 `lib` 了。

Expand Down
4 changes: 2 additions & 2 deletions src/safe-guides/coding_practice/cargo/G.CAR.02.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
**【反例】**

```toml
# This `Cargo.toml` is missing a description field:
# `Cargo.toml` 缺失介绍(description)项。无法发布到 crates.io。
[package]
name = "clippy"
version = "0.0.212"
Expand All @@ -24,7 +24,7 @@ categories = ["development-tools", "development-tools::cargo-plugins"]
**【正例】**

```toml
# This `Cargo.toml` includes all common metadata
# `Cargo.toml` 包含必要元信息。
[package]
name = "clippy"
version = "0.0.212"
Expand Down
2 changes: 1 addition & 1 deletion src/safe-guides/coding_practice/cargo/P.CAR.01.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@

但需要注意,crate 之间的依赖关系应该是单向的,避免相互依赖的情况。

但 Rust 中 编译时间、性能、编译大小之间,在考虑优化的时候也是需要权衡的。
但 Rust 中编译时间、性能、编译大小之间,在考虑优化的时候也是需要权衡的。

内联是优化的关键,当编译单元越大,内联优化效果就越好。所以需要权衡 crate 划分的粒度。
2 changes: 1 addition & 1 deletion src/safe-guides/coding_practice/cargo/P.CAR.03.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

**【描述】**

考虑将条件编译 `--cfg` 使用 `cargo features` 代替,使用 Rust 原生的条件编译兼容性更好些
`cargo features` Rust 原生的条件编译,可用于代替 `--cfg` 参数且兼容性更好
2 changes: 1 addition & 1 deletion src/safe-guides/coding_practice/macros/P.MAC.01.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**【描述】**

能使用宏写出强大和用户友好的宏API的人,重点不仅是因为他们对宏如何实现掌握的好,而是因为他们同时也掌握了宏之外关于 Rust 的一切。
当一个开发者想要能写出强大且用户友好的宏API时,不仅需要掌握如何用宏去实现,更需要掌握宏之外关于 Rust 的一切。

宏设计的重点在于宏生成什么样的代码,而不是宏如何生成代码。

Expand Down
2 changes: 1 addition & 1 deletion src/safe-guides/coding_practice/macros/P.MAC.02.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**【描述】**

Rust 宏可以让开发者定义自己的DSL,但是在使用宏的时候,要尽可能贴近Rust的语法。这样可以增强可读性,让其他开发者在使用宏的时候,可以猜测出它的生成的代码
Rust 宏可以让开发者定义自己的 DSL,但是在使用宏的时候,要尽可能贴近 Rust 的语法。这样可以增强可读性,让其他开发者在使用宏的时候,可以猜测出它生成的代码

**【反例】**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**【描述】**

`macro_rules!` 定义声明宏时,非终止的元变量匹配必须紧随一个已被决定可以在这种匹配之后安全使用的标记
`macro_rules!` 定义声明宏时,非终止的元变量匹配必须紧随一个已被决定能在这种匹配之后安全使用的标记

具体的规则参见:[Follow-set Ambiguity Restrictions](https://doc.rust-lang.org/reference/macros-by-example.html#follow-set-ambiguity-restrictions)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

**【描述】**

使用宏替换(substitution)元变量,就是指把已经进行过宏解析的 token 再次传给宏,需要注意,此时传入的 token已经被看作是宏解析器解析后的 AST 节点了。
使用宏替换(substitution)元变量,就是指把已经进行过宏解析的 token 再次传给宏,需要注意此时传入的 token 已经被看作是宏解析器解析后的 AST 节点了。

片段分类符介绍([fragment-specifier](https://doc.rust-lang.org/nightly/reference/macros-by-example.html#metavariables))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ struct Dummy(i32);

impl Dummy {
fn double(self) -> Dummy {
make_mutable!(self); // 这里传入的 self 和宏内部 let 定义的 self 不是一码事
make_mutable!(self); // 这里传入的 self 和宏内部 let 定义的 self 不同
self.0 *= 2;
self
}
Expand Down
14 changes: 7 additions & 7 deletions src/safe-guides/coding_practice/macros/proc.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

syn/quote 不仅能用于过程宏,还广泛用于代码生成(*codegen*)、静态分析等用途,例如 tonic-build/prost 源码中也用到了 syn/quote 。

因此本过程宏规范不仅适用于过程宏,部分规范(例如 [P.MAC.Proc.06](./macros/proc/P.MAC.Proc.06.md))还适用于 prost 这种代码生成库
因此本过程宏规范不仅适用于过程宏,部分规范(例如 [P.MAC.PRO.06](./proc/P.MAC.PRO.06.md)) 还适用于 prost 这种代码生成库

过程宏必须被单独定义在一个类型为`proc-macro` 的 crate 中。

Expand All @@ -18,9 +18,9 @@ syn/quote 不仅能用于过程宏,还广泛用于代码生成(*codegen*)、

## 列表

- [P.MAC.PRO.01 不要使用过程宏来规避静态分析检查](.proc/P.MAC.PRO.01.md)
- [P.MAC.PRO.02 实现过程宏时要对关键特性增加测试](.proc/P.MAC.PRO.02.md)
- [P.MAC.PRO.03 保证过程宏的卫生性](.proc/P.MAC.PRO.03.md)
- [P.MAC.PRO.04 给出正确的错误位置](.proc/P.MAC.PRO.04.md)
- [P.MAC.PRO.05 代码生成要按情况选择使用过程宏还是 build.rs](.proc/P.MAC.PRO.05.md)
- [P.MAC.PRO.06 build.rs 生成的代码要保证没有任何警告](.proc/P.MAC.PRO.06.md)
- [P.MAC.PRO.01 不要使用过程宏来规避静态分析检查](./proc/P.MAC.PRO.01.md)
- [P.MAC.PRO.02 实现过程宏时要对关键特性增加测试](./proc/P.MAC.PRO.02.md)
- [P.MAC.PRO.03 保证过程宏的卫生性](./proc/P.MAC.PRO.03.md)
- [P.MAC.PRO.04 给出正确的错误位置](./proc/P.MAC.PRO.04.md)
- [P.MAC.PRO.05 代码生成要按情况选择使用过程宏还是 build.rs](./proc/P.MAC.PRO.05.md)
- [P.MAC.PRO.06 build.rs 生成的代码要保证没有任何警告](./proc/P.MAC.PRO.06.md)
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
- Early bound。一般情况下,`'a: 'b` 以及 `impl<'a>` 这种方式是 early bound,意味着这些生命周期参数会在当前作用域单态化生命周期实例。
- Late bound。默认的 `'a` 或 `for<'a>` 是在实际调用它们的地方才单态化生命周期实例。

在不同的场景下,需要指定合适的单态化方式,才能让编译器明白开发者的意图。
在不同的场景下需要指定合适的单态化方式,才能让编译器明白开发者的意图。

在使用匿名生命周期 `'_` 的时候需要注意,如果有多个匿名生命周期,比如 `('_,'_)` ,每个匿名生命周期都会有自己的单独实例。

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

**【描述】**

不要认为无锁编程性能就一定高,使用时需要注意的地方比使用同步锁都多,比如指令重排、ABA 问题、内存顺序是否指定正确等
无锁编程性能不一定比同步锁高

正确实现无锁编程比使用同步锁要困难很多。所以,除非有必要,否则直接使用同步锁就可以。
使用无锁编程时需要注意的地方比使用同步锁多,比如指令重排、ABA 问题、内存顺序是否指定正确等。
正确实现无锁编程比使用同步锁要困难很多。所以,除非必要,否则直接使用同步锁就可以。

也有一些 [性能测试](https://github.com/magiclen/rust-performance-measurement/blob/master/benches/atomic_mutex.rs) 作为参考,原子类型的性能比互斥锁的性能大概要好四倍左右。所以,当在同一个临界区内要有超过四次原子操作,也许使用互斥锁更加简单一些。
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ Rust 原子类型使用 [`C++20` 的内存顺序模型](https://zh.cppreference.
目前 Rust 引入五种内存顺序:`Relaxed / Release / Acquire / AcqRel / SeqCst`。

在无锁编程中,指定正确的内存顺序是很重要很复杂的一件事,这里有一些建议:
1. 如果你对程序中的原子类型同步方式的判断没有太多信息,建议你使用 `SeqCst`,它表示顺序一致性,会强制所有线程都同意程序指令以单一全局线性的方式来执行。这样可以保证安全性,但性能有一定损失。
2. 如果你对无锁实现中线程间发生的数据竞争带来的后果不是特别关心,则可以放心使用 `Relaxed`,因为它性能最好。
1. 如果对程序中的原子类型同步方式的判断没有太多信息,建议使用 `SeqCst`,它表示顺序一致性,会强制所有线程都同意程序指令以单一全局线性的方式来执行。这样可以保证安全性,但性能有一定损失。
2. 如果对无锁实现中线程间发生的数据竞争带来的后果不是特别关心,则可以放心使用 `Relaxed`,因为它性能最好。
3. 当多个线程之间操作内存中同一个位置有因果关系时,适合使用 `Acquire / Release / AcqRel` 来配对。比如,线程 A 写 (`Release`) 内存中的一个位置,然后线程 B 随后读 (`Acquire`) 内存中一个相同的位置,就会产生一个因果关系,所以为了保证 A 的每次写入都能在 B 读取之前被观察到。如果 A 和 B 访问不同内存位置,则没有因果关系。

**【正例】**
Expand Down