wip: 2024 edition

main
kazeno 2 days ago
parent 7bf2039ec4
commit 54ca9ae3bf

@ -65,7 +65,7 @@ fn first_word(s: &String) -> ?
fn second_word(s: &String) -> (usize, usize) {
```
现在我们要跟踪一个开始索引 **和** 一个结尾索引,同时有了更多从数据的某个特定状态计算而来的值,但都完全没有与这个状态相关联。现在有三个飘忽不定的不相关变量需要保持同步。
现在我们要跟踪一个开始索引**和**一个结束索引,同时有了更多从数据的某个特定状态计算而来的值,但都完全没有与这个状态相关联。现在有三个飘忽不定的不相关变量需要保持同步。
幸运的是Rust 为这个问题提供了一个解决方法:字符串 slice。
@ -120,7 +120,7 @@ let slice = &s[0..len];
let slice = &s[..];
```
> 注意:字符串 slice range 的索引必须位于有效的 UTF-8 字符边界内,如果尝试从一个多字节字符的中间位置创建字符串 slice则程序将会因错误而退出。出于介绍字符串 slice 的目的,本部分假设只使用 ASCII 字符集;第八章的 [“使用字符串储存 UTF-8 编码的文本”][strings] 部分会更加全面的讨论 UTF-8 处理问题。
> 注意:字符串 slice range 的索引必须位于有效的 UTF-8 字符边界内,如果尝试从一个多字节字符的中间位置创建字符串 slice则程序将会因错误而退出。
在记住所有这些知识后,让我们重写 `first_word` 来返回一个 slice。“字符串 slice” 的类型声明写作 `&str`
@ -156,8 +156,6 @@ fn second_word(s: &String) -> &str {
回忆一下借用规则,当拥有某值的不可变引用时,就不能再获取一个可变引用。因为 `clear` 需要清空 `String`,它尝试获取一个可变引用。在调用 `clear` 之后的 `println!` 使用了 `word` 中的引用所以这个不可变的引用在此时必须仍然有效。Rust 不允许 `clear` 中的可变引用和 `word` 中的不可变引用同时存在因此编译失败。Rust 不仅使得我们的 API 简单易用,也在编译时就消除了一整类的错误!
<a id="string-literals-are-slices"></a>
#### 字符串字面值就是 slice
还记得我们讲到过字符串字面值被储存在二进制文件中吗?现在知道 slice 了,我们就可以正确地理解字符串字面值了:

@ -1,9 +1,8 @@
# 使用结构体组织相关联的数据
> [ch05-00-structs.md](https://github.com/rust-lang/book/blob/main/src/ch05-00-structs.md)
> <br>
> commit 8612c4a5801b61f8d2e952f8bbbb444692ff1ec2
<!-- https://github.com/rust-lang/book/blob/main/src/ch05-00-structs.md -->
<!-- commit 3a30e4c1fbe641afc066b3af9eb01dcdf5ed8b24 -->
*struct*,或者 *structure*,是一个自定义数据类型,允许你包装和命名多个相关的值,从而形成一个有意义的组合。如果你熟悉一门面向对象语言,*struct* 就像对象中的数据属性。在本章中,我们会对元组和结构体进行比较和对比。
**结构体***struct*,或者 *structure*,是一个自定义数据类型,允许你包装和命名多个相关的值,从而形成一个有意义的组合。如果你熟悉一门面向对象语言,*struct* 就像对象中的数据属性。在本章中,我们会对元组和结构体进行比较和对比,来全建立已有的知识,并演示在何种情况下结构体是组合数据的更好方式
我们还将演示如何定义和实例化结构体,并讨论如何定义关联函数,特别是被称为 *方法* 的那种关联函数,以指定与结构体类型相关的行为。你可以在程序中基于结构体和枚举(*enum*)(在第六章介绍)创建新类型,以充分利用 Rust 的编译时类型检查。

@ -1,8 +1,7 @@
## 结构体的定义和实例化
> [ch05-01-defining-structs.md](https://github.com/rust-lang/book/blob/main/src/ch05-01-defining-structs.md)
> <br>
> commit a371f82b0916cf21de2d56bd386ca5d72f7699b0
<!-- https://github.com/rust-lang/book/blob/main/src/ch05-01-defining-structs.md -->
<!-- commit e4681b573677380154825f383546b68e6111a725 -->
结构体和我们在[“元组类型”][tuples]部分论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
@ -90,11 +89,11 @@
示例 5-7 中的代码也在 `user2` 中创建了一个新实例,但该实例中 `email` 字段的值与 `user1` 不同,而 `username``active``sign_in_count` 字段的值与 `user1` 相同。`..user1` 必须放在最后,以指定其余的字段应从 `user1` 的相应字段中获取其值,但我们可以选择以任何顺序为任意字段指定值,而不用考虑结构体定义中字段的顺序。
请注意,结构更新语法就像带有 `=` 的赋值,因为它移动了数据,就像我们在[“使用移动的变量与数据交互”][move]部分讲到的一样。在这个例子中,总体上说我们在创建 `user2` 后就不能再使用 `user1` 了,因为 `user1``username` 字段中的 `String` 被移到 `user2` 中。如果我们给 `user2``email``username` 都赋予新的 `String` 值,从而只使`user1``active``sign_in_count` 值,那么 `user1` 在创建 `user2` 后仍然有效。`active` 和 `sign_in_count` 的类型是实现 `Copy` trait 的类型,所以我们在[“使用克隆的变量与数据交互”][copy] 部分讨论的行为同样适用。
请注意,结构更新语法就像带有 `=` 的赋值,因为它移动了数据,就像我们在[“使用移动的变量与数据交互”][move]部分讲到的一样。在这个例子中,总体上说我们在创建 `user2` 后就不能再使用 `user1` 了,因为 `user1``username` 字段中的 `String` 被移到 `user2` 中。如果我们给 `user2``email``username` 都赋予新的 `String` 值,从而只`user1``active``sign_in_count` 值,那么 `user1` 在创建 `user2` 后仍然有效。`active` 和 `sign_in_count` 的类型是实现 `Copy` trait 的类型,所以我们在[“使用克隆的变量与数据交互”][copy] 部分讨论的行为同样适用。在本例中我们也可以继续使用 `user1.email`,因为它的值并未从 `user1` 中移动出去。
### 使用没有命名字段的元组结构体来创建不同的类型
也可以定义与元组(在第三章讨论过)类似的结构体,称为 **元组结构体***tuple structs*)。元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,这时像常规结构体那样为每个字段命名就显得多余和形式化了。
也可以定义与元组类似的结构体,称为 **元组结构体***tuple structs*)。元组结构体有着结构体名称提供的含义,但没有具体的字段名,只有字段的类型。当你想给整个元组取一个名字,并使元组成为与其他元组不同的类型时,元组结构体是很有用的,这时像常规结构体那样为每个字段命名就显得多余和形式化了。
要定义元组结构体,以 `struct` 关键字和结构体名开头并后跟元组中的类型。例如,下面是两个分别叫做 `Color``Point` 元组结构体的定义和用法:
@ -104,11 +103,11 @@
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs}}
```
注意 `black``origin` 值的类型不同,因为它们是不同的元组结构体的实例。你定义的每一个结构体有其自己的类型,即使结构体中的字段可能有着相同的类型。例如,一个获取 `Color` 类型参数的函数不能接受 `Point` 作为参数,即便这两个类型都由三个 `i32` 值组成。在其他方面,元组结构体实例类似于元组,你可以将它们解构为单独的部分,也可以使用 `.` 后跟索引来访问单独的值,等等
注意 `black``origin` 值的类型不同,因为它们是不同的元组结构体的实例。你定义的每一个结构体有其自己的类型,即使结构体中的字段可能有着相同的类型。例如,一个获取 `Color` 类型参数的函数不能接受 `Point` 作为参数,即便这两个类型都由三个 `i32` 值组成。除此之外,元组结构体实例类似于元组,你可以将它们解构为单独的部分,也可以使用 `.` 后跟索引来访问单独的值。与元组不同的是,解构元组结构体时必须写明结构体的类型。例如,我们可以写 `let Point(x, y, z) = origin;`,将 `origin` 的值解构到名为 `x`、`y` 和 `z` 的变量中
### 没有任何字段的类单元结构体
我们也可以定义一个没有任何字段的结构体!它们被称为 **类单元结构体***unit-like structs*)因为它们类似于 `()`,即[“元组类型”][tuples]一节中提到的 unit 类型。类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。我们将在第十章介绍 trait。下面是一个声明和实例化一个名为 `AlwaysEqual` 的 unit 结构的例子。
我们也可以定义一个没有任何字段的结构体!它们被称为 **类单元结构体***unit-like structs*)因为它们类似于 `()`,即[“元组类型”][tuples]一节中提到的 unit 类型。类单元结构体常常在你想要在某个类型上实现 trait 但不需要在类型中存储数据的时候发挥作用。我们将在第十章介绍 trait。下面是一个声明和实例化一个名为 `AlwaysEqual` 的 unit 结构的示例:
<span class="filename">文件名src/main.rs</span>
@ -116,13 +115,13 @@
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/src/main.rs}}
```
为了定义 `AlwaysEqual`,我们使用 `struct` 关键字,接着是我们想要的名称,然后是一个分号。不需要花括号或圆括号!然后,我们可以以类似的方式在 `subject` 变量中创建 `AlwaysEqual` 的实例:只需使用我们定义的名称,无需任何花括号或圆括号。设想我们稍后将为这个类型实现某种行为,使得每个 `AlwaysEqual` 的实例始终等于任何其它类型的实例,也许是为了获得一个已知的结果以便进行测试。我们不需要任何数据来实现这种行为!在第十章中,你会看到如何定义特征并在任何类型上实现它们,包括类单元结构体。
为了定义 `AlwaysEqual`,我们使用 `struct` 关键字,接着是我们想要的名称,然后是一个分号。不需要花括号或圆括号!然后,我们可以以类似的方式在 `subject` 变量中创建 `AlwaysEqual` 的实例:只需使用我们定义的名称,无需任何花括号或圆括号。设想我们稍后将为这个类型实现某种行为,使得每个 `AlwaysEqual` 的实例始终等于任何其它类型的实例,也许是为了获得一个已知的结果以便进行测试。我们不需要任何数据来实现这种行为!在第十章中,你会看到如何定义 trait 并在任何类型上实现它们,包括类单元结构体。
> ### 结构体数据的所有权
>
> 在示例 5-1 中的 `User` 结构体的定义中,我们使用了自身拥有所有权的 `String` 类型而不是 `&str` 字符串 slice 类型。这是一个有意而为之的选择,因为我们想要这个结构体拥有它所有的数据,为此只要整个结构体是有效的话其数据也是有效的。
>
> 可以使结构体存储被其他对象拥有的数据的引用,不过这么做的话需要用上 **生命周期***lifetimes*),这是一个第十章会讨论的 Rust 功能。生命周期确保结构体引用的数据有效性跟结构体本身保持一致。如果你尝试在结构体中存储一个引用而不指定生命周期将是无效的,比如这样:
> 可以使结构体存储被其他对象拥有的数据的引用,不过这么做的话需要用上 **生命周期***lifetimes*),这是一个第十章会讨论的 Rust 特性。生命周期确保结构体引用的数据有效性跟结构体本身保持一致。如果你尝试在结构体中存储一个引用而不指定生命周期将是无效的,比如这样:
>
> <span class="filename">文件名src/main.rs</span>
>
@ -177,7 +176,7 @@
> |
>
> For more information about this error, try `rustc --explain E0106`.
> error: could not compile `structs` due to 2 previous errors
> error: could not compile `structs` (bin "structs") due to 2 previous errors
> ```
>
> 第十章会讲到如何修复这个问题以便在结构体中存储引用,不过现在,我们会使用像 `String` 这类拥有所有权的类型来替代 `&str` 这样的引用以修正这个错误。

@ -1,8 +1,7 @@
## 结构体示例程序
> [ch05-02-example-structs.md](https://github.com/rust-lang/book/blob/main/src/ch05-02-example-structs.md)
> <br>
> commit 8612c4a5801b61f8d2e952f8bbbb444692ff1ec2
<!-- https://github.com/rust-lang/book/blob/main/src/ch05-02-example-structs.md -->
<!-- commit 02e053cdbbb3bf9edd9ad32ed49eb533404350a9 -->
为了理解何时会需要使用结构体,让我们编写一个计算长方形面积的程序。我们会从单独的变量开始,接着重构程序直到使用结构体替代它们为止。

Loading…
Cancel
Save