update to ch-02

pull/736/head
KaiserY 1 year ago
parent 5424e85354
commit d157604fed

@ -71,7 +71,8 @@
我们将各个模块的代码移动到独立文件了,同时模块树依旧相同。`eat_at_restaurant` 中的函数调用也无需修改继续保持有效,即便其定义存在于不同的文件中。这个技巧让你可以在模块代码增长时,将它们移动到新文件中。
注意,*src/lib.rs* 中的 `pub use crate::front_of_house::hosting` 语句是没有改变的,在文件作为 crate 的一部分而编译时,`use` 不会有任何影响。`mod` 关键字声明了模块Rust 会在与模块同名的文件中查找模块的代码。
注意,*src/lib.rs* 中的 `pub use crate::front_of_house::hosting` 语句也并未发生改变。use 也不会对哪些文件会被编译为 crate 的一部分有任何影响。`mod` 关键字声明了模块,而 Rust 会在与模块同名的文件中查找模块的代码。
## 总结

@ -150,7 +150,7 @@ src/libcore/result.rs:906:4
函数体以调用 `File::open` 函数开始。接着使用 `match` 处理返回值 `Result`,类似示例 9-4如果 `File::open` 成功了,模式变量 `file` 中的文件句柄就变成了可变变量 `username_file` 中的值,接着函数继续执行。在 `Err` 的情况下,我们没有调用 `panic!`,而是使用 `return` 关键字提前结束整个函数,并将来自 `File::open` 的错误值(现在在模式变量 `e` 中)作为函数的错误值传回给调用者。
所以 `username_file` 中有了一个文件句柄,数接着在变量 `username` 中创建了一个新 `String` 并调用文件句柄 `username_file``read_to_string` 方法来将文件的内容读取到 `username` 中。`read_to_string` 方法也返回一个 `Result` 因为它也可能会失败:哪怕是 `File::open` 已经成功了。所以我们需要另一个 `match` 来处理这个 `Result`:如果 `read_to_string` 成功了,那么这个函数就成功了,并返回文件中的用户名,它现在位于被封装进 `Ok``username` 中。如果`read_to_string` 失败了,则像之前处理 `File::open` 的返回值的 `match` 那样返回错误值。不过并不需要显式调用 `return`,因为这是函数的最后一个表达式。
所以如果 `username_file` 中有了一个文件句柄,数接着在变量 `username` 中创建了一个新 `String` 并调用文件句柄 `username_file``read_to_string` 方法来将文件的内容读取到 `username` 中。`read_to_string` 方法也会返回一个 `Result`,因为它可能会失败,哪怕是 `File::open` 已经成功了。所以我们需要另一个 `match` 来处理这个 `Result`:如果 `read_to_string` 成功了,那么这个函数就成功了,并返回文件中的用户名,它现在位于被封装进 `Ok``username` 中。如果`read_to_string` 失败了,则像之前处理 `File::open` 的返回值的 `match` 那样返回错误值。不过并不需要显式调用 `return`,因为这是函数的最后一个表达式。
调用这个函数的代码最终会得到一个包含用户名的 `Ok` 值,或者一个包含 `io::Error``Err` 值。我们无从得知调用者会如何处理这些值。例如,如果他们得到了一个 `Err` 值,他们可能会选择 `panic!` 并使程序崩溃、使用一个默认的用户名或者从文件之外的地方寻找用户名。我们没有足够的信息知晓调用者具体会如何尝试,所以将所有的成功或失败信息向上传播,让他们选择合适的处理方法。

@ -22,7 +22,7 @@
`largest_i32` 函数是从示例 10-3 中摘出来的,它用来寻找 slice 中最大的 `i32`。`largest_char` 函数寻找 slice 中最大的 `char`。因为两者函数体的代码是一样的,我们可以定义一个函数,再引进泛型参数来消除这种重复。
为了参数化这个新函数中的这些类型,我们也需要为类型参数取个名字,道理和给函数的形参起名一样。任何标识符都可以作为类型参数的名字。这里选用 `T`因为传统上来说Rust 的参数名字都比较短,通常就只有一个字母同时Rust 类型名的命名规范是首字母大写驼峰式命名法UpperCamelCase。`T` 作为 “type” 的缩写是大部分 Rust 程序员的首选。
为了参数化这个新函数中的这些类型,我们需要为类型参数命名,道理和给函数的形参起名一样。任何标识符都可以作为类型参数的名字。这里选用 `T`因为传统上来说Rust 的类型参数名字都比较短,通常仅为一个字母同时Rust 类型名的命名规范是首字母大写驼峰式命名法UpperCamelCase。`T` 作为 “type” 的缩写是大部分 Rust 程序员的首选。
如果要在函数体中使用参数,就必须在函数签名中声明它的名字,好让编译器知道这个名字指代的是什么。同理,当在函数签名中使用一个类型参数时,必须在使用它之前就声明它。为了定义泛型版本的 `largest` 函数,类型参数声明位于函数名称与参数列表中间的尖括号 `<>` 中,像这样:

@ -218,7 +218,7 @@ let s = 3.to_string();
blanket implementation 会出现在 trait 文档的 “Implementers” 部分。
trait 和 trait bound 让我们使用泛型类型参数来减少重复,并仍然能够向编译器明确指定泛型类型需要拥有哪些行为。因为我们向编译器提供了 trait bound 信息,它就可以检查代码中所用到的具体类型是否提供了正确的行为。在动态类型语言中,如果我们尝试调用一个类型并没有实现的方法会在运行时出现错误。Rust 将这些错误移动到了编译时,甚至在代码能够运行之前就强迫我们修复错误。另外,我们也无需编写运行时检查行为的代码,因为在编译时就已经检查过了,这样相比其他那些不愿放弃泛型灵活性的语言有更好的性能
trait 和 trait bound 让我们能够使用泛型类型参数来减少重复,而且能够向编译器明确指定泛型类型需要拥有哪些行为。然后编译器可以利用 trait bound 信息检查代码中所用到的具体类型是否提供了正确的行为。在动态类型语言中,如果我们调用了一个未定义的方法会在运行时出现错误。Rust 将这些错误移动到了编译时,甚至在代码能够运行之前就强迫我们修复问题。另外,我们也无需编写运行时检查行为的代码,因为在编译时就已经检查过了。这样既提升了性能又不必放弃泛型的灵活性
[using-trait-objects-that-allow-for-values-of-different-types]:
ch17-02-trait-objects.html#为使用不同类型的值而设计的-trait-对象

Loading…
Cancel
Save