diff --git a/src/afterword.md b/src/afterword.md index 3143e3d..41708cb 100644 --- a/src/afterword.md +++ b/src/afterword.md @@ -13,8 +13,8 @@ -[第 33 条]: https://www.lurklurk.org/effective-rust/no-std.html -[第 34 条]: https://www.lurklurk.org/effective-rust/ffi.html +[第 33 条]: chapter_6/item33-no-std.md +[第 34 条]: chapter_6/item34-ffi.md [在线文档]: https://rust-lang.github.io/async-book/ [异步 Rust]: https://learning.oreilly.com/library/view/async-rust/9781098149086/ diff --git a/src/chapter_1/item1-use-types.md b/src/chapter_1/item1-use-types.md index 4899ee8..8bac166 100644 --- a/src/chapter_1/item1-use-types.md +++ b/src/chapter_1/item1-use-types.md @@ -282,11 +282,11 @@ struct DisplayProperties { -[第 3 条]: ./item3-transform.md -[第 4 条]: ./item4-errors.md -[第 5 条]: ./item5-casts.md -[第 6 条]: ./item6-newtype.md -[第 7 条]: ./item7-builder.md +[第 3 条]: item3-transform.md +[第 4 条]: item4-errors.md +[第 5 条]: item5-casts.md +[第 6 条]: item6-newtype.md +[第 7 条]: item7-builder.md [第 16 条]: ../chapter_3/item16-unsafe.md [第 18 条]: ../chapter_3/item18-panic.md [第 21 条]: ../chapter_4/item21-semver.md diff --git a/src/chapter_1/item2-use-types-2.md b/src/chapter_1/item2-use-types-2.md index 2de5c64..9e43f64 100644 --- a/src/chapter_1/item2-use-types-2.md +++ b/src/chapter_1/item2-use-types-2.md @@ -1,6 +1,6 @@ # 第 2 条:使用类型系统表达常见行为 -[第1条]讨论了如何在类型系统中表达数据结构;本节继续讨论在 Rust 的类型系统中行为的编码。 +[第 1 条]讨论了如何在类型系统中表达数据结构;本节继续讨论在 Rust 的类型系统中行为的编码。 本条目所描述的机制通常会让人感觉熟悉,因为它们在其他语言中都有直接的类似物: @@ -11,7 +11,7 @@ - 特征(Traits):描述适用于同一基础项的相关功能的集合。在许多其他语言中都有大致等效的概念,包括 C++ 中的抽象类以及 Go 和 Java 中的接口。 当然,所有这些机制都有Rust特定的细节,本条将会一一介绍。 -在前面列出的内容中,特征(traits)对于本书来说意义最为重大,因为它们描述了 Rust 编译器和标准库提供的很多行为。[第2章] 重点讨论了关于设计和实现特征的相关内容,但它们的普遍性意味着它们在本章的其他条目中也会频繁出现。 +在前面列出的内容中,特征(traits)对于本书来说意义最为重大,因为它们描述了 Rust 编译器和标准库提供的很多行为。[第 2 章] 重点讨论了关于设计和实现特征的相关内容,但它们的普遍性意味着它们在本章的其他条目中也会频繁出现。 ## 函数和方法( Function and Methods ) @@ -35,7 +35,7 @@ fn show(x: f64) { ``` -如果一个函数与特定的数据结构密切相关,它就表现为一个方法。方法通过 self 标识,对该类型实例进行操作,并包含在 impl DataStructure 块中。这以类似于其他语言的面向对象方式将相关数据和代码封装在一起;然而,在 Rust 中,方法不仅可以添加到`结构体`类型上,也可以添加到`枚举`类型上,这与 Rust 枚举的普遍性质相符([第1条])。 +如果一个函数与特定的数据结构密切相关,它就表现为一个方法。方法通过 self 标识,对该类型实例进行操作,并包含在 impl DataStructure 块中。这以类似于其他语言的面向对象方式将相关数据和代码封装在一起;然而,在 Rust 中,方法不仅可以添加到`结构体`类型上,也可以添加到`枚举`类型上,这与 Rust 枚举的普遍性质相符([第 1 条])。 ```rust enum Shape { @@ -124,7 +124,7 @@ help: you might have forgotten to call this function 相反,编译器错误表明该类型类似于 `fn(i32, i32) -> i32 {main::sum}`,一种完全内部于编译器的类型(即不能在用户代码中编写),它同时标识了特定的函数及其签名。 -换句话说,`sum` 的类型既编码了函数的签名又编码了其位置(出于优化原因);这种类型可以自动强制转换为 `fn` 类型([第6条])。 +换句话说,`sum` 的类型既编码了函数的签名又编码了其位置(出于优化原因);这种类型可以自动强制转换为 `fn` 类型([第 6 条])。 ### 闭包 @@ -218,7 +218,7 @@ let z = add_n.internal_op(5); assert_eq!(z, 8); ``` -在这个概念性的上下文中持有的值通常是引用([第9条]),就像这里的例子,但它们也可以是环境中事物的可变引用,或者是通过在输入参数前使用 `move` 关键字而从环境中完全移出的值。 +在这个概念性的上下文中持有的值通常是引用([第 9 条]),就像这里的例子,但它们也可以是环境中事物的可变引用,或者是通过在输入参数前使用 `move` 关键字而从环境中完全移出的值。 回到 `modify_all` 的例子,闭包不能用在期望函数指针的地方。 @@ -278,7 +278,7 @@ Rust 有三种不同的 `Fn*` 特征,它们之间表达了关于环境捕获 特征中的每个方法也有一个名称,这允许编译器区分具有相同签名的方法,更重要的是,它允许程序员推断方法的目的。 -Rust 的特征大致类似于 Go 和 Java 中的“接口”,或者 C++ 中的“抽象类”(只有虚拟方法,没有数据成员)。特征的实现必须提供所有方法(但请注意特征定义可以包括默认的实现,[第13条]),并且还可以有相关联的数据,那些实现会使用这些数据。这意味着代码和数据在共同的抽象中以某种面向对象的方式一起封装。 +Rust 的特征大致类似于 Go 和 Java 中的“接口”,或者 C++ 中的“抽象类”(只有虚拟方法,没有数据成员)。特征的实现必须提供所有方法(但请注意特征定义可以包括默认的实现,[第 13 条]),并且还可以有相关联的数据,那些实现会使用这些数据。这意味着代码和数据在共同的抽象中以某种面向对象的方式一起封装。 接受结构体并调用其方法的代码被限制只能与特定类型一起工作。如果有多个类型实现了公共行为,那么定义一个特征来封装这种行为,并让代码使用特征的方法而不是特定结构体的方法会更加灵活。 @@ -303,7 +303,7 @@ pub trait StableSort: Sort {} 一旦行为被封装到 Rust 的类型系统中作为一个特征,它可以以两种方式被使用: - 作为特征约束(`trait bound`),它在编译时限制了哪些类型可以被一个泛型数据类型或方法所接受,或者 - 作为特征对象(`trait object`),它在运行时限制了哪些类型可以被存储或传递给一个方法。 -[第12条] 更详细地讨论了这两种方式的权衡。 +[第 12 条] 更详细地讨论了这两种方式的权衡。 ## 特征约束 @@ -419,12 +419,12 @@ note: for a trait to be "object safe" it needs to allow building a vtable to all -[第1条]: item1-use-types.md -[第2章]: /chapter_2//item10-std-traits.md -[第6条]: item6-newtype.md -[第9条]: item9-iterators.md -[第12条]: /chapter_2/item12-generics&trait-objects.md -[第13条]: /chapter_2/item13-use-default-impl.md +[第 1 条]: item1-use-types.md +[第 2 章]: ../chapter_2.md +[第 6 条]: item6-newtype.md +[第 9 条]: item9-iterators.md +[第 12 条]: ../chapter_2/item12-generics&trait-objects.md +[第 13 条]: ../chapter_2/item13-use-default-impl.md [函数指针]: https://doc.rust-lang.org/std/primitive.fn.html [鸭子类型]: https://en.wikipedia.org/wiki/Duck_typing diff --git a/src/chapter_1/item3-transform.md b/src/chapter_1/item3-transform.md index ec9b330..f671d35 100644 --- a/src/chapter_1/item3-transform.md +++ b/src/chapter_1/item3-transform.md @@ -1,8 +1,8 @@ # 第 3 条:优先选择Option和Result转换,而非显式匹配表达式 -[第1条] 阐述了枚举(`enum`)的优点,并展示了 `match` 表达式如何强制程序员考虑所有可能性;这个方法探讨了在某些情况下,你应尽量避免使用 `match` 表达式 —— 至少是显式地。 +[第 1 条] 阐述了枚举(`enum`)的优点,并展示了 `match` 表达式如何强制程序员考虑所有可能性;这个方法探讨了在某些情况下,你应尽量避免使用 `match` 表达式 —— 至少是显式地。 -[第1条] 还介绍了 Rust 标准库提供的两个无处不在的枚举: +[第 1 条] 还介绍了 Rust 标准库提供的两个无处不在的枚举: - `Option`,表示一个值(类型为 `T`)可能存在也可能不存在。 - `Result`,用于当尝试返回一个值(类型为 `T`)的操作可能失败,并可能返回一个错误(类型为 `E`)。 @@ -30,8 +30,9 @@ if let Some(i) = &s.field { } ``` -然而,大多数时候,程序员通常的处理方式是提供相应的else分支:缺少值( `Option::None` ),或者返回一个可能会出现相关错误( `Result::Err(e)` )。设计能够应对失败路径的软件是困难的,而且其中大部分是本质的复杂性,无论多少语法支持都无法帮助——具体来说,就是决定如果一个操作失败了应该发生什么。 -在某些情况下,正确的决定是采取“鸵鸟策略”——把我们的头埋进沙子里,明确地不去处理失败。你不能完全忽略错误分支,因为Rust要求代码必须处理`Error`枚举的两种变体,但你可以选择将失败视为致命的错误。在失败时执行一个`panic!`意味着程序会终止,但可以在成功的假设下来编写其余的代码。通过显式`match`来执行此操作会不必要地冗长: +然而,大多数时候,程序员通常的处理方式是提供相应的 `else` 分支:缺少值(`Option::None`),或者返回一个可能会出现的相关错误(`Result::Err(e)`)。设计能够应对失败路径的软件是困难的,而且其中大部分是本质的复杂性,无论多少语法支持都无法帮助——具体来说,就是决定如果一个操作失败了应该发生什么。 + +在某些情况下,正确的决定是采取“鸵鸟策略”——把我们的头埋进沙子里,明确地不去处理失败。你不能完全忽略错误分支,因为 Rust 要求代码必须处理 `Error` 枚举的两种变体,但你可以选择将失败视为致命的错误。在失败时执行一个 `panic!` 意味着程序会终止,但可以在成功的假设下来编写其余的代码。通过显式 `match` 来执行此操作会不必要地冗长: ```rust let result = std::fs::File::open("/etc/passwd"); @@ -40,13 +41,16 @@ let f = match result { Err(_e) => panic!("Failed to open /etc/passwd!"), }; ``` -当值不存在时,`Option`和`Result`都提供了一对方法来提取它们的内部值和`panic!`,它们分别是 [unwrap](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap)和[expect](https://doc.rust-lang.org/std/result/enum.Result.html#method.expect) 。后者允许个性化失败时的错误消息,但无论哪种情况,将错误处理被委托给`.unwrap()`后缀(但仍然存在)生成的代码都更短、更简单: + +`Option` 和 `Result` 都提供了一对方法来提取它们的内部值并在值不存在时执行 `panic!`,它们分别是 [unwrap](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap) 和 [expect](https://doc.rust-lang.org/std/result/enum.Result.html#method.expect) 。后者允许个性化失败时的错误消息,并将错误处理委托给 `.unwrap()` 后缀,但无论哪种情况,生成的代码都更短、更简单: + ```rust let f = std::fs::File::open("/etc/passwd").unwrap(); ``` -但要明确的是:这些辅助函数仍然会引发 `panic!`,所以选择使用它们与选择直接 `panic!`([第18条])是一样的。 -然而,在许多情况下,正确的错误处理是将决策推迟给其他人。这在编写库时尤其如此,因为库的代码可能会在库作者无法预见的各种不同环境中使用。为了使库更易用,优先使用 `Result` 而不是 `Option`来表示错误,即使这可能涉及不同错误类型之间的转换([第4条])。 +但要明确的是:这些辅助函数仍然会引发 `panic!`,所以选择使用它们与选择直接 `panic!`([第 18 条])是一样的。 + +然而,在许多情况下,正确的错误处理是将决策推迟给其他人。这在编写库时尤其如此,因为库的代码可能会在库作者无法预见的各种不同环境中使用。为了使库更易用,优先使用 `Result` 而不是 `Option` 来表示错误,即使这可能涉及不同错误类型之间的转换([第 4 条])。 当然,这提出了一个问题:什么算作错误?在此示例中,无法打开文件肯定是一个错误,并且该错误的详细信息(没有此类文件?权限被拒绝?)可以帮助用户决定下一步要做什么。另一方面,由于切片为空而未能检索切片的first()元素并不是真正的错误,因此它在标准库中表示为Option返回类型。 在两种可能性之间进行选择需要判断,但如果错误可能传达任何有用的信息,则倾向于Result 。 @@ -86,7 +90,7 @@ pub fn find_user(username: &str) -> Result { } ``` -Rust 新手有时会对此感到困惑:问号运算符在一开始很难被注意到,导致人们怀疑这段代码怎么可能正常工作。然而,即使只有一个字符,类型系统仍然在起作用,确保覆盖了相关类型([第1条])表达的所有可能性——让程序员可以专注于主线代码路径,不受干扰。 +Rust 新手有时会对此感到困惑:问号运算符在一开始很难被注意到,导致人们怀疑这段代码怎么可能正常工作。然而,即使只有一个字符,类型系统仍然在起作用,确保覆盖了相关类型([第 1 条])表达的所有可能性——让程序员可以专注于主线代码路径,不受干扰。 更重要的是,这些明显的方法调用通常没有额外的成本:它们都是标记为 `#[inline]` 的泛型函数,所以生成的代码通常会编译成与手动版本相同的机器代码。 @@ -94,7 +98,7 @@ Rust 新手有时会对此感到困惑:问号运算符在一开始很难被注 在之前的例子中,错误类型是一致的:内部和外部方法都使用 `std::io::Error` 表达错误。然而,情况往往并非如此;一个函数可能从各种不同的子库中累积错误,每个子库都使用不同的错误类型。 -关于错误映射的讨论一般见[第4条];现在,只需知道一个手动映射: +关于错误映射的讨论一般见[第 4 条];现在,只需知道一个手动映射: ```rust pub fn find_user(username: &str) -> Result { @@ -118,11 +122,11 @@ pub fn find_user(username: &str) -> Result { } ``` -更好的是,甚至这可能也不必要 —— 如果外部错误类型可以通过实现标准特征 `From`([第5条])从内部错误类型创建,那么编译器将自动执行转换,无需调用 `.map_err()`。 +更好的是,甚至这可能也不必要 —— 如果外部错误类型可以通过实现标准特征 `From`([第 5 条])从内部错误类型创建,那么编译器将自动执行转换,无需调用 `.map_err()`。 这类转换具有更广泛的通用性。问号运算符是一个强大的工具;使用 `Option` 和 `Result` 类型上的转换方法将它们调整到可以顺利处理的形态。 -标准库提供了各种各样的转换方法来实现这一点,如下面的地图所示。根据[第18条],可能引发 `panic!` 的方法用红色突出显示。 +标准库提供了各种各样的转换方法来实现这一点,如下面的地图所示。根据[第 18 条],可能引发 `panic!` 的方法用红色突出显示。 ![转换方法](../images/transform.svg) @@ -186,9 +190,9 @@ pub fn encrypted(&self) -> Vec { -[第1条]: item1-use-types.md -[第4条]: item4-errors.md -[第5条]: item5-casts.md -[第18条]: https://www.lurklurk.org/effective-rust/panic.html +[第 1 条]: item1-use-types.md +[第 4 条]: item4-errors.md +[第 5 条]: item5-casts.md +[第 18 条]: ../chapter_3/item18-panic.md [在线版本]: https://tinyurl.com/rust-transform diff --git a/src/chapter_1/item4-errors.md b/src/chapter_1/item4-errors.md index 8e6639e..78908e4 100644 --- a/src/chapter_1/item4-errors.md +++ b/src/chapter_1/item4-errors.md @@ -333,13 +333,13 @@ error[E0119]: conflicting implementations of trait `From` for [第 3 条]: item3-transform.md [第 5 条]: item5-casts.md [第 6 条]: item6-newtype.md -[第 10 条]: https://www.lurklurk.org/effective-rust/std-traits.html -[第 12 条]: /chapter_2/item12-generics&trait-objects.md -[第 13 条]: /chapter_2/item13-use-default-impl.md -[第 24 条]: https://www.lurklurk.org/effective-rust/re-export.html -[第 25 条]: https://www.lurklurk.org/effective-rust/dep-graph.html -[第 28 条]: https://www.lurklurk.org/effective-rust/macros.html -[第 33 条]: https://www.lurklurk.org/effective-rust/no-std.html +[第 10 条]: ../chapter_2/item10-std-traits.md +[第 12 条]: ../chapter_2/item12-generics&trait-objects.md +[第 13 条]: ../chapter_2/item13-use-default-impl.md +[第 24 条]: ../chapter_4/item24-re-export.md +[第 25 条]: ../chapter_4/item25-dep-graph.md +[第 28 条]: ../chapter_5/item28-use-macros-judiciously.md +[第 33 条]: ../chapter_6/item33-no-std.md [anyhow]:https://docs.rs/anyhow [thiserror]:https://docs.rs/thiserror diff --git a/src/chapter_1/item5-casts.md b/src/chapter_1/item5-casts.md index 47f7126..bfe6a9d 100644 --- a/src/chapter_1/item5-casts.md +++ b/src/chapter_1/item5-casts.md @@ -237,6 +237,6 @@ error[E0277]: the trait bound `u16: From` is not satisfied [第 4 条]: item4-errors.md [第 6 条]: item6-newtype.md [第 8 条]: item8-references&pointer.md -[第 10 条]: https://www.lurklurk.org/effective-rust/std-traits.html -[第 14 条]: https://www.lurklurk.org/effective-rust/lifetimes.html -[第 29 条]: https://www.lurklurk.org/effective-rust/clippy.html +[第 10 条]: ../chapter_2/item10-std-traits.md +[第 14 条]: ../chapter_3/item14-lifetimes.md +[第 29 条]: ../chapter_5/item29-listen-to-clippy.md diff --git a/src/chapter_1/item6-newtype.md b/src/chapter_1/item6-newtype.md index 92ac1cc..3da81c8 100644 --- a/src/chapter_1/item6-newtype.md +++ b/src/chapter_1/item6-newtype.md @@ -241,7 +241,7 @@ impl fmt::Display for NewType { [第 1 条]: item1-use-types.md [第 5 条]: item5-casts.md -[第 25 条]: https://www.lurklurk.org/effective-rust/dep-graph.html +[第 25 条]: ../chapter_4/item25-dep-graph.md [常见]: https://doc.rust-lang.org/book/ch19-03-advanced-traits.html#using-the-newtype-pattern-to-implement-external-traits-on-external-types [额外的语义]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction diff --git a/src/chapter_1/item7-builder.md b/src/chapter_1/item7-builder.md index 75c1fef..d4d9b03 100644 --- a/src/chapter_1/item7-builder.md +++ b/src/chapter_1/item7-builder.md @@ -346,9 +346,9 @@ pub fn build(&self) -> Details { -[第 10 条]:https://www.lurklurk.org/effective-rust/std-traits.html -[第 25 条]:https://www.lurklurk.org/effective-rust/dep-graph.html -[第 28 条]:https://www.lurklurk.org/effective-rust/macros.html +[第 10 条]: ../chapter_2/item10-std-traits.md +[第 25 条]: ../chapter_4/item25-dep-graph.md +[第 28 条]: ../chapter_5/item28-use-macros-judiciously.md [Default]:https://doc.rust-lang.org/std/default/trait.Default.html [derive_builder]:https://docs.rs/derive_builder/latest/derive_builder/ \ No newline at end of file diff --git a/src/chapter_1/item8-references&pointer.md b/src/chapter_1/item8-references&pointer.md index d908d63..0b2205f 100644 --- a/src/chapter_1/item8-references&pointer.md +++ b/src/chapter_1/item8-references&pointer.md @@ -6,14 +6,14 @@ 然而,高级编程语言通常会在其类型系统中编码更多关于指针的信息。在 C 衍生的语言(包括 Rust )中,指针中有一个类型,该类型表示期望在所指向的内存地址存储哪种类型数据结构。这允许通过代码解释在该地址以及随后内存中的内容。 -这种基本的指针信息-假定的内存位置和预期的数据结构布局-在 Rust 中被表示为一个**裸指针(raw point)**。然而,安全的 Rust 代码不使用裸指针,因为 Rust 提供了更丰富的引用和指针类型,这些类型提供了额外的安全保证和约束。这些引用和指针类型是本节的主题;裸指针则留待[第16条]讨论(该节讨论 unsafe 代码)。 +这种基本的指针信息-假定的内存位置和预期的数据结构布局-在 Rust 中被表示为一个**裸指针(raw point)**。然而,安全的 Rust 代码不使用裸指针,因为 Rust 提供了更丰富的引用和指针类型,这些类型提供了额外的安全保证和约束。这些引用和指针类型是本节的主题;裸指针则留待[第 16 条]讨论(该节讨论 unsafe 代码)。 ## Rust引用 在 Rust 中,最常见的指针类型是 *引用*,用 `&T` 表示,其中 `T` 是任意类型。尽管在底层这是一个指针值,但编译器会确保在使用时遵循一些规则: - 始终指向有效且对齐正确的类型 `T` 的实例。 -- 被引用数据的生命周期(在[第14条]中介绍)必须比 *引用* 本身的生命周期更长。 -- 遵守借用检查规则(在[第15条]中解释)。 +- 被引用数据的生命周期(在[第 14 条]中介绍)必须比 *引用* 本身的生命周期更长。 +- 遵守借用检查规则(在[第 15 条]中解释)。 这些额外的约束总是隐含在 Rust 中的 *引用* 中,因此 *裸指针* 通常很少出现。 @@ -98,7 +98,7 @@ show(&box_pt); 这之所以可能,因为 `Box` 实现了 [`Deref`] 特征(`Trait`),`Target = T`。某个类型实现这个特征意味着该特征的 [`deref()`] 方法可以用于创建对 `Target` 类型的引用。还有一个等效的 [`DerefMut`] 特征,它会生成对 `Target` 类型的**可变**引用。 -`Deref`/`DerefMut` 特征有点特别,因为Rust编译器在处理实现它们的类型时有特定的行为。当编译器遇到解引用表达式(例如,[`*x`]),它会根据解引用是否需要可变访问来查找并使用这些特征的实现。这种 `Deref` 转换允许各种智能指针类型像普通引用一样工作,它是 Rust 中少数允许隐式类型转换的机制之一(如[第5条]所述)。 +`Deref`/`DerefMut` 特征有点特别,因为Rust编译器在处理实现它们的类型时有特定的行为。当编译器遇到解引用表达式(例如,[`*x`]),它会根据解引用是否需要可变访问来查找并使用这些特征的实现。这种 `Deref` 转换允许各种智能指针类型像普通引用一样工作,它是 Rust 中少数允许隐式类型转换的机制之一(如[第 5 条]所述)。 作为一个技术细节,理解为什么 `Deref` 特征不能对目标类型是泛型的(`Deref`)是很值得的。如果它们是,那么某些类型 `ConfusedPtr` 就可以同时实现 `Deref` 和 `Deref`,这将使编译器无法为 `*x` 这样的表达式推导出唯一的类型。因此,目标类型被编码为一个名为 `Target` 的关联类型。 这种技术细节与另两个标准指针特征 [`AsRef`] 和 [`AsMut`] 形成对比。这些特征不会在编译器中引起特殊行为,但允许通过对其特征函数([`as_ref()`] 和 [`as_mut()`])的显式调用进行引用或可变引用的转换。转换的目标类型被编码为类型参数(例如,`AsRef`),这意味着一个容器类型可以支持多个目标类型。 @@ -152,7 +152,7 @@ let vslice = &vector[1..3]; #### 特征对象 -第二种内置的胖指针类型是特征对象:它引用实现了特定特征的某个元素。特征对象由一个指向该元素的简单指针和一个指向类型 [`vtable`] 的内部指针共同构成,大小为 16 字节(在 64 位平台上)。类型的 `vtable` 存储了该类型所实现特征的方法实现的函数指针,从而允许在运行时进行动态分配([第12条])。[^3] +第二种内置的胖指针类型是特征对象:它引用实现了特定特征的某个元素。特征对象由一个指向该元素的简单指针和一个指向类型 [`vtable`] 的内部指针共同构成,大小为 16 字节(在 64 位平台上)。类型的 `vtable` 存储了该类型所实现特征的方法实现的函数指针,从而允许在运行时进行动态分配([第 12 条])。[^3] 例如,定义一个简单的特征: @@ -193,7 +193,7 @@ assert_eq!(result, 1); ![img](../images/item8/traitobject.svg) 图1-6.指向具体项和 `vtable` 的 Trait 对象 -持有特征对象的代码可以通过 `vtable` 中的函数指针调用特征的方法,并将元素指针作为 `&self` 参数传递;有关更多信息和建议,请参考[第12条]。 +持有特征对象的代码可以通过 `vtable` 中的函数指针调用特征的方法,并将元素指针作为 `&self` 参数传递;有关更多信息和建议,请参考[第 12 条]。 ## 更多指针特征 @@ -251,7 +251,7 @@ let wk = Rc::downgrade(&rc1); Rc 本身允许你以不同的方式访问一个项,但是当你访问该项时,只有在没有其他方式访问该项时(即,没有其他现存的 `Rc`或 `Weak` 引用指向同一项),你才能修改它(通过 [`get_mut`])。这很难协调,因此 `Rc` 通常与 `RefCell` 结合使用。 -下一个智能指针类型是[`RefCell`],它放宽了只能由所有者或持有唯一可变引用的代码修改数据的规则(参考[第15条])。这种内部可变性带来了更大的灵活性,例如允许特征实现修改内部,即使方法签名只允许 `&self`。然而,这也带来了代价:除了额外的存储开销(需要一个额外的 `isize` 用于跟踪当前的借用,如图 1-8 所示),正常的借用检查也从编译时转移到了运行时: +下一个智能指针类型是[`RefCell`],它放宽了只能由所有者或持有唯一可变引用的代码修改数据的规则(参考[第 15 条])。这种内部可变性带来了更大的灵活性,例如允许特征实现修改内部,即使方法签名只允许 `&self`。然而,这也带来了代价:除了额外的存储开销(需要一个额外的 `isize` 用于跟踪当前的借用,如图 1-8 所示),正常的借用检查也从编译时转移到了运行时: ```rust use std::cell::RefCell; @@ -266,11 +266,11 @@ let b2 = rc.borrow(); 这些运行时的借用检查意味着用户使用 `RefCell` 时,必须在两个不愉快的选项之间做出选择: - 接受借用可能失败的操作,并处理来自 `try_borrow[_mut]` 的 Result 值。 -- 使用所谓不会失败的借用方法 `borrow[_mut]`,并接受在运行时由于借用规则不合规而引发 panic 的风险(参考[第18条])。 +- 使用所谓不会失败的借用方法 `borrow[_mut]`,并接受在运行时由于借用规则不合规而引发 panic 的风险(参考[第 18 条])。 无论哪种情况,这种运行时检查意味着 `RefCell` 不实现任何标准指针特征;相反,它的访问操作返回一个实现了这些特征的 [`Ref`] 或 [`RefMut`] 智能指针类型。 -如果底层类型 `T` 实现了 `Copy` 特征(表示按位快速复制生成一个有效的项;参考[第10条]),那么 `Cell` 类型允许以更少的开销进行内部修改——`get(&self)` 方法复制出当前值,`set(&self, val)` 方法设置一个新值进去。`Cell` 类型在 `Rc` 和 `RefCell` 实现中都被内部使用,用于共享跟踪可以修改的计数器,而无需 `&mut self`。 +如果底层类型 `T` 实现了 `Copy` 特征(表示按位快速复制生成一个有效的项;参考[第 10 条]),那么 `Cell` 类型允许以更少的开销进行内部修改——`get(&self)` 方法复制出当前值,`set(&self, val)` 方法设置一个新值进去。`Cell` 类型在 `Rc` 和 `RefCell` 实现中都被内部使用,用于共享跟踪可以修改的计数器,而无需 `&mut self`。 到目前为止描述的智能指针类型仅适用于单线程使用;它们的实现假设对其内部没有并发访问。如果不是这种情况,则需要包含额外同步开销的智能指针。 @@ -280,7 +280,7 @@ let b2 = rc.borrow(); 如果读者(读操作线程)可能多于写者(写操作线程),则更推荐使用 [`RwLock`] 类型,因为它允许多个读者并行访问底层项目,前提是当前没有(单个)写者。 -在任何情况下,Rust 的借用和线程规则都强制在多线程代码中使用这些同步容器中的一个(但这仅能防止共享状态并发的一些问题;参考[第17条])。 +在任何情况下,Rust 的借用和线程规则都强制在多线程代码中使用这些同步容器中的一个(但这仅能防止共享状态并发的一些问题;参考[第 17 条])。 对于其他智能指针类型,有时也可以应用相同的策略——查看编译器拒绝的内容,并替换为它建议的内容。然而,更快、更少挫折的方法是理解不同智能指针的行为含义。借用来自[`Rust编程语言第一版的示例`]: - `Rc>>` 持有一个具有共享所有权 (`Rc`) 的 `Vec`,其中 `Vec` 可以作为一个整体被修改。 @@ -296,14 +296,14 @@ let b2 = rc.borrow(); [^4]: 请注意,这并不影响 Rust 的内存安全保证:项目仍然是安全的,只是无法访问 -[第5条]: item5-casts.md -[第10条]: https://www.lurklurk.org/effective-rust/std-traits.html -[第12条]: /chapter_2/item12-generics&trait-objects.md -[第14条]: https://www.lurklurk.org/effective-rust/lifetimes.html -[第15条]: https://www.lurklurk.org/effective-rust/borrows.html -[第16条]: https://www.lurklurk.org/effective-rust/unsafe.html -[第17条]: https://www.lurklurk.org/effective-rust/deadlock.html -[第18条]: https://www.lurklurk.org/effective-rust/panic.html +[第 5 条]: item5-casts.md +[第 10 条]: ../chapter_2/item10-std-traits.md +[第 12 条]: ../chapter_2/item12-generics&trait-objects.md +[第 14 条]: ../chapter_3/item14-lifetimes.md +[第 15 条]: ../chapter_3/item15-borrows.md +[第 16 条]: ../chapter_3/item16-unsafe.md +[第 17 条]: ../chapter_3/item17-deadlock.md +[第 18 条]: ../chapter_3/item18-panic.md [`Deref`]: https://doc.rust-lang.org/std/ops/trait.Deref.html [`deref()`]: https://doc.rust-lang.org/std/ops/trait.Deref.html#tymethod.deref diff --git a/src/chapter_1/item9-iterators.md b/src/chapter_1/item9-iterators.md index 3b0f880..2ee05e9 100644 --- a/src/chapter_1/item9-iterators.md +++ b/src/chapter_1/item9-iterators.md @@ -479,10 +479,10 @@ let even_sum_squares: u64 = values [第 3 条]: item3-transform.md -[第 10 条]: https://www.lurklurk.org/effective-rust/std-traits.html -[第 13 条]: /chapter_2/item13-use-default-impl.md -[第 15 条]: https://www.lurklurk.org/effective-rust/borrows.html -[第 30 条]: https://www.lurklurk.org/effective-rust/testing.html +[第 10 条]: ../chapter_2/item10-std-traits.md +[第 13 条]: ../chapter_2/item13-use-default-impl.md +[第 15 条]: ../chapter_3/item15-borrows.md +[第 30 条]: ../chapter_5/item30-write-more-than-unit-tests.md [Java 1.5]:https://docs.oracle.com/javase/1.5.0/docs/guide/language/foreach.html [Iterator]:https://doc.rust-lang.org/core/iter/trait.Iterator.html diff --git a/src/chapter_2.md b/src/chapter_2.md index c10b2dc..d3d464a 100644 --- a/src/chapter_2.md +++ b/src/chapter_2.md @@ -7,4 +7,4 @@ Rust 类型系统的第二个核心支柱是特征(`traits`)的使用,它 -[第 12 条]: https://www.lurklurk.org/effective-rust/generics.html +[第 12 条]: ../chapter_2/item12-generics&trait-objects.md diff --git a/src/chapter_2/item10-std-traits.md b/src/chapter_2/item10-std-traits.md index ca11e85..52360d8 100644 --- a/src/chapter_2/item10-std-traits.md +++ b/src/chapter_2/item10-std-traits.md @@ -371,17 +371,17 @@ if x <= y { 3:这里的一些名称有点隐晦——例如 `Rem` 是求余数,`Shl` 是按位左移——但是 [std::ops] 的文档清楚第说明了它们的预期行为。 -[第 2 条]:https://www.lurklurk.org/effective-rust/use-types-2.html -[第 4 条]:https://www.lurklurk.org/effective-rust/errors.html -[第 5 条]:https://www.lurklurk.org/effective-rust/casts.html -[第 7 条]:https://www.lurklurk.org/effective-rust/builders.html -[第 8 条]:https://www.lurklurk.org/effective-rust/references.html -[第 9 条]:https://www.lurklurk.org/effective-rust/iterators.html -[第 11 条]:https://www.lurklurk.org/effective-rust/raii.html -[第 12 条]:https://www.lurklurk.org/effective-rust/generics.html -[第 15 条]:https://www.lurklurk.org/effective-rust/borrows.html -[第 17 条]:https://www.lurklurk.org/effective-rust/deadlock.html -[第 29 条]:https://www.lurklurk.org/effective-rust/clippy.html +[第 2 条]: ../chapter_1/item2-use-types-2.md +[第 4 条]: ../chapter_1/item4-errors.md +[第 5 条]: ../chapter_1/item5-casts.md +[第 7 条]: ../chapter_1/item7-builder.md +[第 8 条]: ../chapter_1/item8-references&pointer.md +[第 9 条]: ../chapter_1/item9-iterators.md +[第 11 条]: ../chapter_2/item11-impl-drop-for-RAII.md +[第 12 条]: ../chapter_2/item12-generics&trait-objects.md +[第 15 条]: ../chapter_3/item15-borrows.md +[第 17 条]: ../chapter_3/item17-deadlock.md +[第 29 条]: ../chapter_5/item29-listen-to-clippy.md [`derive` macros]:https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros [add_assign]:https://doc.rust-lang.org/std/ops/trait.AddAssign.html#tymethod.add_assign diff --git a/src/chapter_2/item11-impl-drop-for-RAII.md b/src/chapter_2/item11-impl-drop-for-RAII.md index 5685716..93d10fc 100644 --- a/src/chapter_2/item11-impl-drop-for-RAII.md +++ b/src/chapter_2/item11-impl-drop-for-RAII.md @@ -177,8 +177,8 @@ error[E0040]: explicit use of destructor method 原文[点这里](https://www.lurklurk.org/effective-rust/raii.html)查看 -[第 15 条]:https://www.lurklurk.org/effective-rust/borrows.html -[第 17 条]:https://www.lurklurk.org/effective-rust/deadlock.html +[第 15 条]: ../chapter_3/item15-borrows.md +[第 17 条]: ../chapter_3/item17-deadlock.md [文件描述符]:https://en.wikipedia.org/wiki/File_descriptor [Mutex::lock()]:https://doc.rust-lang.org/std/sync/struct.Mutex.html#method.lock diff --git a/src/chapter_2/item12-generics&trait-objects.md b/src/chapter_2/item12-generics&trait-objects.md index 98952b2..d1deec2 100644 --- a/src/chapter_2/item12-generics&trait-objects.md +++ b/src/chapter_2/item12-generics&trait-objects.md @@ -1,6 +1,6 @@ # 第 12 条:理解泛型和特征对象之间的权衡 -[第2条]描述了如何使用特征来封装类型系统中的行为,作为相关方法的集合,并观察到有两种使用特征的方法:作为泛型的特征约束( `trait bound` )或特征对象( `trait object` )。本条探讨了这两种可能性之间的权衡。 +[第 2 条]描述了如何使用特征来封装类型系统中的行为,作为相关方法的集合,并观察到有两种使用特征的方法:作为泛型的特征约束( `trait bound` )或特征对象( `trait object` )。本条探讨了这两种可能性之间的权衡。 下面是一个运行示例,请考虑一个涵盖显示图形对象的功能的特征: @@ -128,7 +128,7 @@ let visible = on_screen(&circle); ## 特征对象 -相比之下,特征对象是一个胖指针([第8条]),它将指向底层具体项目的指针与指向虚表(vtable)的指针结合在一起,而虚表又持有特征实现的所有方法的函数指针,如图 2-1 所示: +相比之下,特征对象是一个胖指针([第 8 条]),它将指向底层具体项目的指针与指向虚表(vtable)的指针结合在一起,而虚表又持有特征实现的所有方法的函数指针,如图 2-1 所示: ![图 2-1](../images/item12/draw.svg "特征对象布局,包含指向具体项目的指针和指向vtable的指针") *图 2-1.特征对象布局,包含指向具体项目的指针和指向vtable的指针* @@ -232,7 +232,7 @@ trait Shape: Draw { } ``` -在本例中,`render()` 方法的默认实现([第13条])使用了特征 `bound`,依赖于 `Draw` 中的 `bounds()` 方法。 +在本例中,`render()` 方法的默认实现([第 13 条])使用了特征 `bound`,依赖于 `Draw` 中的 `bounds()` 方法。 来自面向对象语言的程序员经常会混淆特征约束和继承,误以为这样的特征约束意味着 `Shape` *就是* `Draw`。事实并非如此:这两种类型之间的关系最好表述为 `Shape` *也实现了* `Draw`。 @@ -251,7 +251,7 @@ let shape: &dyn Shape = □ ![图 2-2](../images/item12/traitbounds.svg "具有`Draw`与`Shape`两种虚表的具有特征约束的特征对象") *图 2-2.具有 `Draw` 与 `Shape` 两种虚表的具有特征约束的特征对象* -在撰写本文时(截至Rust 1.70版本),没有办法从 `Shape` 向上转型到 `Draw`,因为无法在运行时恢复(纯净的) `Draw` 虚表;没有办法在相关的特征对象之间进行转换,这反过来又意味着没有[里氏替换原则(Liskov substitution)]。然而,这种情况很可能在 Rust 的后续版本中发生变化——有关更多信息,请参见[第19条]。 +在撰写本文时(截至Rust 1.70版本),没有办法从 `Shape` 向上转型到 `Draw`,因为无法在运行时恢复(纯净的) `Draw` 虚表;没有办法在相关的特征对象之间进行转换,这反过来又意味着没有[里氏替换原则(Liskov substitution)]。然而,这种情况很可能在 Rust 的后续版本中发生变化——有关更多信息,请参见[第 19 条]。 用不同的语言重复同样的观点,接受 `Shape` 特征对象的方法具有以下特征: - 它可以使用 `Draw` 的方法(因为 `Shape` 也实现了 `Draw`,而且 `Shape` 虚表中存在相关函数指针)。 @@ -269,7 +269,7 @@ let shape: &dyn Shape = □ 第一个限制很容易理解:泛型方法 `f` 是一组无限多的方法,可能包含 `f::`, `f::`, `f::`, `f::` 等。另一方面,特征对象的虚表在很大程度上是指针函数的有限集合,因此不可能将无限的单态实现集放入其中。 -第二种限制比较微妙,但往往是在实践中更常遇到的限制--使用 `Copy` 或 `Clone` 特征约束([第10条])的特征会立即受到这条规则的限制,因为它们返回的是 `Self`。如果代码调用(例如) `let y = x.clone()`,会发生什么情况?调用代码需要在堆栈中为 `y` 预留足够的空间,但它不知道 `y` 的大小,因为 `Self` 是一个任意类型。因此,提及 `Self` 的返回类型会导致特征对对象不安全[^2]。 +第二种限制比较微妙,但往往是在实践中更常遇到的限制--使用 `Copy` 或 `Clone` 特征约束([第 10 条])的特征会立即受到这条规则的限制,因为它们返回的是 `Self`。如果代码调用(例如) `let y = x.clone()`,会发生什么情况?调用代码需要在堆栈中为 `y` 预留足够的空间,但它不知道 `y` 的大小,因为 `Self` 是一个任意类型。因此,提及 `Self` 的返回类型会导致特征对对象不安全[^2]。 第二个限制有一个例外。如果 `Self` 对编译时已知大小的类型有明确的限制,即 `Sized` 标记特征作为特征,那么返回某种 `Self` 相关类型的方法就不会影响对象的安全性: @@ -318,7 +318,7 @@ error: the `make_copy` method cannot be invoked on a trait object 首先是实际考虑:如果生成代码的大小或编译时间是个问题,那么特征对象的性能会更好(如本项目前面所述)。 -从理论上讲,特征对象从根本上涉及类型擦除:在转换为特征对象的过程中,具体类型的信息会丢失。这可能是一个缺点(见[第19条]),但它也可能是有用的,因为它允许异构对象的集合--因为代码只依赖于特质的方法,它可以调用和组合具有不同具体类型的项的方法。 +从理论上讲,特征对象从根本上涉及类型擦除:在转换为特征对象的过程中,具体类型的信息会丢失。这可能是一个缺点(见[第 19 条]),但它也可能是有用的,因为它允许异构对象的集合--因为代码只依赖于特质的方法,它可以调用和组合具有不同具体类型的项的方法。 渲染形状列表的传统面向对象例子就是一个例子:在同一个循环中,可以对正方形、圆形、椭圆形和星形使用相同的 `render()` 方法: @@ -339,11 +339,11 @@ for shape in shapes { [^2]: 在撰写本文时,对返回 `Self` 的方法的限制包括像 `Box ` 这样可以安全地存储在堆栈中的类型;这一限制将来可能会放宽。 -[第2条]: /chapter_1/item2-use-types-2.md -[第8条]: /chapter_1/item8-references&pointer.md -[第10条]: https://www.lurklurk.org/effective-rust/std-traits.html -[第13条]: item13-use-default-impl.md -[第19条]: https://www.lurklurk.org/effective-rust/reflection.html +[第 2 条]: ../chapter_1/item2-use-types-2.md +[第 8 条]: ../chapter_1/item8-references&pointer.md +[第 10 条]: ../chapter_2/item10-std-traits.md +[第 13 条]: ../chapter_2/item13-use-default-impl.md +[第 19 条]: ../chapter_3/item19-reflection.md [里氏替换原则(Liskov substitution)]: https://en.wikipedia.org/wiki/Liskov_substitution_principle [对象安全]: https://doc.rust-lang.org/reference/items/traits.html#object-safety diff --git a/src/chapter_2/item13-use-default-impl.md b/src/chapter_2/item13-use-default-impl.md index 7ce6691..8a7833c 100644 --- a/src/chapter_2/item13-use-default-impl.md +++ b/src/chapter_2/item13-use-default-impl.md @@ -19,7 +19,7 @@ fn is_empty(&self) -> bool { 这种方法使得 trait 定义具有少量必需的方法,以及大量默认实现的方法。实现者只需实现前者,即可随意使用所有后者。 -Rust 标准库广泛采用了这种方法;[Iterator] trait 就是一个很好的例子,它只有一个必需方法( [next()] ),但包含了大量预提供的方法( [第9条] ),撰写本文时已经超过50个。 +Rust 标准库广泛采用了这种方法;[Iterator] trait 就是一个很好的例子,它只有一个必需方法( [next()] ),但包含了大量预提供的方法([第 9 条]),撰写本文时已经超过50个。 trait 方法可以添加 trait 约束,这意味着只有在相关类型实现特定 trait 时,目标方法才可用。这在结合默认方法实现时非常有用,[Iterator] 也印证了这点。例如,[cloned()] 的迭代器方法有一个 trait 约束和一个默认实现: @@ -35,15 +35,15 @@ where 换句话说,`cloned()` 方法只有在 `Item` 的类型实现了 [Clone] trait 时才可用;一旦实现 `Clone` trait, `clone()` 方法也会自动实现。 -关于带有默认实现的 trait 方法,最后一个要点是,即使在特征的初始版本发布之后,通常也可以安全地向 trait 添加新方法。只要新方法名不与类型实现的其他 trait 方法名冲突,就能保持向后兼容性(详见 [第21条])。 +关于带有默认实现的 trait 方法,最后一个要点是,即使在特征的初始版本发布之后,通常也可以安全地向 trait 添加新方法。只要新方法名不与类型实现的其他 trait 方法名冲突,就能保持向后兼容性(详见 [第 21 条])。 因此,请参照标准库的示例,通过添加带有默认实现的方法(并根据需要添加 trait 约束),为实现者提供最少的 API 接口,但为用户提供方便且全面的 API 。 原文[点这里](https://www.lurklurk.org/effective-rust/default-impl.html)查看 -[第9条]: chapter_1/item9-iterators.md -[第21条]: https://www.lurklurk.org/effective-rust/semver.html +[第 9 条]: ../chapter_1/item9-iterators.md +[第 21 条]: ../chapter_4/item21-semver.md [is_empty()]:https://doc.rust-lang.org/std/iter/trait.ExactSizeIterator.html#method.is_empty [ExactSizeIterator]:https://doc.rust-lang.org/std/iter/trait.ExactSizeIterator.html diff --git a/src/chapter_3.md b/src/chapter_3.md index f79846e..dc1f91b 100644 --- a/src/chapter_3.md +++ b/src/chapter_3.md @@ -15,8 +15,8 @@ -[第 16 条]: https://www.lurklurk.org/effective-rust/unsafe.html -[第 17 条]: https://www.lurklurk.org/effective-rust/deadlock.html -[第 18 条]: https://www.lurklurk.org/effective-rust/panic.html -[第 19 条]: https://www.lurklurk.org/effective-rust/reflection.html -[第 20 条]: https://www.lurklurk.org/effective-rust/optimize.html +[第 16 条]: chapter_3/item16-unsafe.md +[第 17 条]: chapter_3/item17-deadlock.md +[第 18 条]: chapter_3/item18-panic.md +[第 19 条]: chapter_3/item19-reflection.md +[第 20 条]: chapter_3/item20-optimize.md diff --git a/src/chapter_3/item14-lifetimes.md b/src/chapter_3/item14-lifetimes.md index 5fb691b..2ea6f8a 100644 --- a/src/chapter_3/item14-lifetimes.md +++ b/src/chapter_3/item14-lifetimes.md @@ -708,10 +708,10 @@ pub trait Debug { -[第 8 条]: /chapter_1/item8-references&pointer.md -[第 11 条]: /chapter_2/item11-impl-drop-for-RAII.md -[第 15 条]: https://www.lurklurk.org/effective-rust/borrows.html -[第 20 条]: https://www.lurklurk.org/effective-rust/optimize.html +[第 8 条]: ../chapter_1/item8-references&pointer.md +[第 11 条]: ../chapter_2/item11-impl-drop-for-RAII.md +[第 15 条]: ../chapter_3/item15-borrows.md +[第 20 条]: ../chapter_3/item20-optimize.md [非词法生命周期]: https://rust-lang.github.io/rfcs/2094-nll.html [static]: https://doc.rust-lang.org/std/keyword.static.html diff --git a/src/chapter_3/item15-borrows.md b/src/chapter_3/item15-borrows.md index bcdb3e7..d268995 100644 --- a/src/chapter_3/item15-borrows.md +++ b/src/chapter_3/item15-borrows.md @@ -797,14 +797,14 @@ struct SelfRefIdx { -[第 1 条]: https://www.lurklurk.org/effective-rust/use-types.html -[第 2 条]: https://www.lurklurk.org/effective-rust/use-types-2.html -[第 8 条]: https://www.lurklurk.org/effective-rust/references.html -[第 10 条]: https://www.lurklurk.org/effective-rust/std-traits.html -[第 14 条]: https://www.lurklurk.org/effective-rust/lifetimes.html -[第 16 条]: https://www.lurklurk.org/effective-rust/unsafe.html -[第 17 条]: https://www.lurklurk.org/effective-rust/deadlock.html -[第 28 条]: https://www.lurklurk.org/effective-rust/macros.html +[第 1 条]: ../chapter_1/item1-use-types.md +[第 2 条]: ../chapter_1/item2-use-types-2.md +[第 8 条]: ../chapter_1/item8-references&pointer.md +[第 10 条]: ../chapter_2/item10-std-traits.md +[第 14 条]: ../chapter_3/item14-lifetimes.md +[第 16 条]: ../chapter_3/item16-unsafe.md +[第 17 条]: ../chapter_3/item17-deadlock.md +[第 28 条]: ../chapter_5/item28-use-macros-judiciously.md [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html [CRUD]: https://en.wikipedia.org/wiki/Create,_read,_update_and_delete [`std::mem::replace`]: https://doc.rust-lang.org/std/mem/fn.replace.html diff --git a/src/chapter_3/item16-unsafe.md b/src/chapter_3/item16-unsafe.md index b064530..435fe0b 100644 --- a/src/chapter_3/item16-unsafe.md +++ b/src/chapter_3/item16-unsafe.md @@ -52,16 +52,16 @@ Rust 标准库包含大量 `unsafe` 代码;快速查找发现 `alloc` 库中 -[第 8 条]: https://www.lurklurk.org/effective-rust/references.html -[第 14 条]: https://www.lurklurk.org/effective-rust/lifetimes.html -[第 15 条]: https://www.lurklurk.org/effective-rust/borrows.html -[第 17 条]: https://www.lurklurk.org/effective-rust/deadlock.html -[第 29 条]: https://www.lurklurk.org/effective-rust/clippy.html -[第 30 条]: https://www.lurklurk.org/effective-rust/testing.html -[第 31 条]: https://www.lurklurk.org/effective-rust/use-tools.html -[第 33 条]: https://www.lurklurk.org/effective-rust/no-std.html -[第 34 条]: https://www.lurklurk.org/effective-rust/ffi.html -[第 35 条]: https://www.lurklurk.org/effective-rust/bindgen.html +[第 8 条]: ../chapter_1/item8-references&pointer.md +[第 14 条]: ../chapter_3/item14-lifetimes.md +[第 15 条]: ../chapter_3/item15-borrows.md +[第 17 条]: ../chapter_3/item17-deadlock.md +[第 29 条]: ../chapter_5/item29-listen-to-clippy.md +[第 30 条]: ../chapter_5/item30-write-more-than-unit-tests.md +[第 31 条]: ../chapter_5/item31-use-tools.md +[第 33 条]: ../chapter_6/item33-no-std.md +[第 34 条]: ../chapter_6/item34-ffi.md +[第 35 条]: ../chapter_6/item35-bindgen.md [《Rust Atomics and Locks》]: https://marabos.nl/atomics/ [`std::pin::Pin`]: https://doc.rust-lang.org/std/pin/struct.Pin.html [bête noire]: https://rust-unofficial.github.io/too-many-lists/ diff --git a/src/chapter_3/item17-deadlock.md b/src/chapter_3/item17-deadlock.md index 95dc908..9b28a8e 100644 --- a/src/chapter_3/item17-deadlock.md +++ b/src/chapter_3/item17-deadlock.md @@ -589,14 +589,14 @@ Go 语言[内置了](https://go.dev/ref/spec#Channel_types)用于这种操作的 -[第 8 条]: https://www.lurklurk.org/effective-rust/references.html -[第 10 条]: https://www.lurklurk.org/effective-rust/std-traits.html -[第 11 条]: https://www.lurklurk.org/effective-rust/raii.html -[第 14 条]: https://www.lurklurk.org/effective-rust/lifetimes.html -[第 15 条]: https://www.lurklurk.org/effective-rust/borrows.html -[第 16 条]: https://www.lurklurk.org/effective-rust/unsafe.html -[第 34 条]: https://www.lurklurk.org/effective-rust/ffi.html -[第 18 条]: ./item18-panic.md +[第 8 条]: ../chapter_1/item8-references&pointer.md +[第 10 条]: ../chapter_2/item10-std-traits.md +[第 11 条]: ../chapter_2/item11-impl-drop-for-RAII.md +[第 14 条]: ../chapter_3/item14-lifetimes.md +[第 15 条]: ../chapter_3/item15-borrows.md +[第 16 条]: ../chapter_3/item16-unsafe.md +[第 34 条]: ../chapter_6/item34-ffi.md +[第 18 条]: item18-panic.md [第 30 条]: ../chapter_5/item30-write-more-than-unit-tests.md [第 32 条]: ../chapter_5/item32-ci.md [“无畏并发”]: https://doc.rust-lang.org/book/ch16-00-concurrency.html diff --git a/src/chapter_3/item18-panic.md b/src/chapter_3/item18-panic.md index 9f21dd5..3437cff 100644 --- a/src/chapter_3/item18-panic.md +++ b/src/chapter_3/item18-panic.md @@ -1,4 +1,4 @@ -# 不要 panic +# 第 18 条:不要 panic > “它看起来非常复杂,这就是为什么它紧凑的塑料盖子上用大大的友好字母写着 DON'T PANIC 的原因之一。”——Douglas Adams @@ -108,11 +108,11 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -[第 4 条]: https://www.lurklurk.org/effective-rust/errors.html +[第 4 条]: ../chapter_1/item4-errors.md [第 27 条]: ../chapter_5/item27-document-public-interfaces.md [第 31 条]: ../chapter_5/item31-use-tools.md [第 32 条]: ../chapter_5/item32-ci.md -[第 34 条]: https://www.lurklurk.org/effective-rust/ffi.html +[第 34 条]: ../chapter_6/item34-ffi.md [`std::panic::catch_unwind`]: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html [编译器选项]: https://doc.rust-lang.org/rustc/codegen-options/index.html#panic [配置文件]: https://doc.rust-lang.org/cargo/reference/profiles.html#panic diff --git a/src/chapter_3/item19-reflection.md b/src/chapter_3/item19-reflection.md index ca076c8..cd9d552 100644 --- a/src/chapter_3/item19-reflection.md +++ b/src/chapter_3/item19-reflection.md @@ -183,11 +183,11 @@ _图 3-5. 用于 trait 约束的 trait 对象,用于 `Draw` 和 `Shape` 的不 -[第 2 条]: https://www.lurklurk.org/effective-rust/use-types-2.html -[第 8 条]: https://www.lurklurk.org/effective-rust/references.html -[第 12 条]: https://www.lurklurk.org/effective-rust/generics.html -[第 25 条]: https://www.lurklurk.org/effective-rust/dep-graph.html -[第 28 条]: https://www.lurklurk.org/effective-rust/macros.html +[第 2 条]: ../chapter_1/item2-use-types-2.md +[第 8 条]: ../chapter_1/item8-references&pointer.md +[第 12 条]: ../chapter_2/item12-generics&trait-objects.md +[第 25 条]: ../chapter_4/item25-dep-graph.md +[第 28 条]: ../chapter_5/item28-use-macros-judiciously.md [Python]: https://docs.python.org/3/library/types.html#module-types [Java]: https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/package-summary.html [Go]: https://golang.org/pkg/reflect/ diff --git a/src/chapter_3/item20-optimize.md b/src/chapter_3/item20-optimize.md index 45a9064..a6673cb 100644 --- a/src/chapter_3/item20-optimize.md +++ b/src/chapter_3/item20-optimize.md @@ -208,8 +208,8 @@ let tlv = Tlv { [^1]: 在 Rust 语言中,你不能将字段命名为 “type”,因为这是一个被保留的关键字。如果你确实需要使用这个名称,可以通过在前面加上 r# 来绕过这个限制(https://oreil.ly/oC8VO),比如将字段命名为 r#type: u8。但大多数情况下,更简单的方法是选择一个不同的字段名称。 -[第 10 条]: /chapter_2/item10-std-traits.md -[第 15 条]: ./item15-borrows.md -[第 17 条]: ./item17-deadlock.md -[第 30 条]: /chapter_5/item30-write-more-than-unit-tests.md -[第 33 条]: https://www.lurklurk.org/effective-rust/testing.html +[第 10 条]: ../chapter_2/item10-std-traits.md +[第 15 条]: ../chapter_3/item15-borrows.md +[第 17 条]: item17-deadlock.md +[第 30 条]: ../chapter_5/item30-write-more-than-unit-tests.md +[第 33 条]: ../chapter_6/item33-no-std.md diff --git a/src/chapter_4/item24-re-export.md b/src/chapter_4/item24-re-export.md index ed28e66..6a7fb7d 100644 --- a/src/chapter_4/item24-re-export.md +++ b/src/chapter_4/item24-re-export.md @@ -1,4 +1,4 @@ -# 第 24 条:重新导出在 API 中所用的依赖项类型 +# 第 24 条:重新导出在 API 中所用的依赖项类型 如果单看本章节的标题,会让人费解。没有关系,下面我们通过一个例子来把事情讲解清楚[^1]。 diff --git a/src/chapter_5/item28-use-macros-judiciously.md b/src/chapter_5/item28-use-macros-judiciously.md index 3b1b2bf..3d87888 100644 --- a/src/chapter_5/item28-use-macros-judiciously.md +++ b/src/chapter_5/item28-use-macros-judiciously.md @@ -611,9 +611,9 @@ let y = log_failure!(std::str::from_utf8(b"\xc3\x28")); // invalid UTF-8 [声明宏]: https://doc.rust-lang.org/reference/macros-by-example.html [cargo-expand]: https://github.com/dtolnay/cargo-expand [fmt 文档]: https://doc.rust-lang.org/std/fmt/index.html -[第 10 条]: https://rustx-labs.github.io/effective-rust-cn/chapter_2/item10-std-traits.html +[第 10 条]: ../chapter_2/item10-std-traits.md [过程宏]: https://doc.rust-lang.org/reference/procedural-macros.html -[第 19 条]: https://www.lurklurk.org/effective-rust/reflection.html +[第 19 条]: ../chapter_3/item19-reflection.md [serd 库]: https://docs.rs/serde/latest/serde/ [Deserialize]: https://docs.rs/serde/latest/serde/derive.Deserialize.html [syn 包]: https://docs.rs/syn/latest/syn/ @@ -622,8 +622,8 @@ let y = log_failure!(std::str::from_utf8(b"\xc3\x28")); // invalid UTF-8 [syn::DeriveInput]: https://docs.rs/syn/latest/syn/struct.DeriveInput.html [file!()]: https://doc.rust-lang.org/std/macro.file.html [line!()]: https://doc.rust-lang.org/std/macro.line.html -[第 31 条]: https://www.lurklurk.org/effective-rust/use-tools.html -[第 25 条]: https://www.lurklurk.org/effective-rust/dep-graph.html +[第 31 条]: ../chapter_5/item31-use-tools.md +[第 25 条]: ../chapter_4/item25-dep-graph.md [enumn::N]: https://docs.rs/enumn/latest/enumn/derive.N.html [num_enum::TryFromPrimitive]: https://docs.rs/enumn/latest/enumn/derive.N.html [num\_derive::FromPrimitive]: https://docs.rs/num-derive/latest/num_derive/derive.FromPrimitive.html diff --git a/src/chapter_5/item30-write-more-than-unit-tests.md b/src/chapter_5/item30-write-more-than-unit-tests.md index e089374..0699f45 100644 --- a/src/chapter_5/item30-write-more-than-unit-tests.md +++ b/src/chapter_5/item30-write-more-than-unit-tests.md @@ -255,10 +255,11 @@ stack backtrace: [编写测试]: https://doc.rust-lang.org/book/ch11-00-testing.html [第 23 条]: ../chapter_4/item23-wildcard.md [第 18 条]: ../chapter_3/item18-panic.md -[第 28 条]: ./item28-use-macros-judiciously.md -[第 27 条]: ./item27-document-public-interfaces.md +[第 28 条]: item28-use-macros-judiciously.md +[第 27 条]: item27-document-public-interfaces.md +[第 20 条]: ../chapter_3/item20-optimize.md [第 21 条]: ../chapter_4/item21-semver.md -[第 32 条]: ./item32-ci.md +[第 32 条]: item32-ci.md [第 3 条]: ../chapter_1/item3-transform.md [cargo test]: https://doc.rust-lang.org/cargo/commands/cargo-bench.html [test]: https://doc.rust-lang.org/unstable-book/library-features/test.html diff --git a/src/chapter_5/item31-use-tools.md b/src/chapter_5/item31-use-tools.md index 5f2aab9..c7471de 100644 --- a/src/chapter_5/item31-use-tools.md +++ b/src/chapter_5/item31-use-tools.md @@ -56,12 +56,12 @@ Rust 工具链的可扩展性不仅限于包元数据;编译器的抽象语法 [第 16 条]: ../chapter_3/item16-unsafe.md [第 21 条]: ../chapter_4/item21-semver.html [第 25 条]: ../chapter_4/item25-dep-graph.md -[第 27 条]: ./item27-document-public-interfaces.md -[第 28 条]: ./item28-use-macros-judiciously.md -[第 29 条]: ./item29-listen-to-clippy.md -[第 30 条]: ./item30-write-more-than-unit-tests.md -[第 32 条]: ./item32-ci.md -[第 35 条]: ../chapter_5/item31-use-tools.md +[第 27 条]: item27-document-public-interfaces.md +[第 28 条]: item28-use-macros-judiciously.md +[第 29 条]: item29-listen-to-clippy.md +[第 30 条]: item30-write-more-than-unit-tests.md +[第 32 条]: item32-ci.md +[第 35 条]: ../chapter_6/item35-bindgen.md [cargo]: https://doc.rust-lang.org/cargo/ [rustup]: https://github.com/rust-lang/rustup diff --git a/src/chapter_6/item35-bindgen.md b/src/chapter_6/item35-bindgen.md index f905e16..f82ec29 100644 --- a/src/chapter_6/item35-bindgen.md +++ b/src/chapter_6/item35-bindgen.md @@ -81,6 +81,6 @@ include!("generated.rs"); [第 16 条]: ../chapter_3/item16-unsafe.md [第 32 条]: ../chapter_5/item32-ci.md -[第 34 条]: https://www.lurklurk.org/effective-rust/ffi.html +[第 34 条]: ../chapter_6/item34-ffi.md [构建脚本]: https://doc.rust-lang.org/cargo/reference/build-scripts.html [`include!` 宏]: https://doc.rust-lang.org/std/macro.include.html diff --git a/src/intro.md b/src/intro.md index 10cf1a3..904032c 100644 --- a/src/intro.md +++ b/src/intro.md @@ -20,7 +20,7 @@ Rust 的安全性也导致完全没有标题为“永远不要…”的条目。 ## Rust 版本 -文本是为2018版的 Rust 编写的,使用稳定工具链。Rust 的后向兼容性承诺意味着任何更高版本的 Rust,包括2021版,仍然会支持为2018版编写的代码,即使那个更高版本引入了破坏性更改。Rust 现在也足够稳定,以至于2018版和2021版之间的差异很小;书中没有任何代码需要更改才能符合2021版(但是[第19条]包括一个例外,其中较晚版本的 Rust 允许以前不可能的新行为)。 +文本是为2018版的 Rust 编写的,使用稳定工具链。Rust 的后向兼容性承诺意味着任何更高版本的 Rust,包括2021版,仍然会支持为2018版编写的代码,即使那个更高版本引入了破坏性更改。Rust 现在也足够稳定,以至于2018版和2021版之间的差异很小;书中没有任何代码需要更改才能符合2021版(但是[第 19 条]包括一个例外,其中较晚版本的 Rust 允许以前不可能的新行为)。 这里的条目没有涵盖 Rust 的任何异步功能方面,因为这涉及到更高级的概念和不那么稳定的工具链支持 —— 使用同步 Rust 已经有足够多的内容要介绍了。也许将来会出现一本《有效的异步Rust》… @@ -78,5 +78,5 @@ Rust 的安全性也导致完全没有标题为“永远不要…”的条目。 [Rust 编程语言]: https://doc.rust-lang.org/book/ [Rust 程序设计]: https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/ -[第19条]: https://www.lurklurk.org/effective-rust/reflection.html +[第 19 条]: chapter_3/item19-reflection.md