@ -2,12 +2,14 @@
> [ch05-01-defining-structs.md ](https://github.com/rust-lang/book/blob/main/src/ch05-01-defining-structs.md )
> [ch05-01-defining-structs.md ](https://github.com/rust-lang/book/blob/main/src/ch05-01-defining-structs.md )
> < br >
> < br >
> commit dd7e05275822d6cf790bcdae6983b3234141b5e7
> commit a371f82b0916cf21de2d56bd386ca5d72f7699b0
结构体和我们在[“元组类型”][tuples]部分论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
结构体和我们在[“元组类型”][tuples]部分论过的元组类似,它们都包含多个相关的值。和元组一样,结构体的每一部分可以是不同类型。但不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字,结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
定义结构体,需要使用 `struct` 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为 ** 字段**( *field*)。例如,示例 5-1 展示了一个存储用户账号信息的结构体:
定义结构体,需要使用 `struct` 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字和类型,我们称为 ** 字段**( *field*)。例如,示例 5-1 展示了一个存储用户账号信息的结构体:
< span class = "filename" > 文件名: src/main.rs< / span >
```rust
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-01/src/main.rs:here}}
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-01/src/main.rs:here}}
```
```
@ -16,6 +18,8 @@
一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 ** 实例**。创建一个实例需要以结构体的名字开头,接着在大括号中使用 `key: value` 键-值对的形式提供字段,其中 key 是字段的名字, value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。例如,可以像示例 5-2 这样来声明一个特定的用户:
一旦定义了结构体后,为了使用它,通过为每个字段指定具体值来创建这个结构体的 ** 实例**。创建一个实例需要以结构体的名字开头,接着在大括号中使用 `key: value` 键-值对的形式提供字段,其中 key 是字段的名字, value 是需要存储在字段中的数据值。实例中字段的顺序不需要和它们在结构体中声明的顺序一致。换句话说,结构体的定义就像一个类型的通用模板,而实例则会在这个模板中放入特定数据来创建这个类型的值。例如,可以像示例 5-2 这样来声明一个特定的用户:
< span class = "filename" > 文件名: src/main.rs< / span >
```rust
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-02/src/main.rs:here}}
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-02/src/main.rs:here}}
```
```
@ -24,6 +28,8 @@
为了从结构体中获取某个特定的值,可以使用点号。举个例子,想要用户的邮箱地址,可以用 `user1.email` 。如果结构体的实例是可变的,我们可以使用点号并为对应的字段赋值。示例 5-3 展示了如何改变一个可变的 `User` 实例中 `email` 字段的值:
为了从结构体中获取某个特定的值,可以使用点号。举个例子,想要用户的邮箱地址,可以用 `user1.email` 。如果结构体的实例是可变的,我们可以使用点号并为对应的字段赋值。示例 5-3 展示了如何改变一个可变的 `User` 实例中 `email` 字段的值:
< span class = "filename" > 文件名: src/main.rs< / span >
```rust
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-03/src/main.rs:here}}
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-03/src/main.rs:here}}
```
```
@ -34,6 +40,8 @@
示例 5-4 显示了一个 `build_user` 函数,它返回一个带有给定的 email 和用户名的 `User` 结构体实例。`active` 字段的值为 `true` ,并且 `sign_in_count` 的值为 `1` 。
示例 5-4 显示了一个 `build_user` 函数,它返回一个带有给定的 email 和用户名的 `User` 结构体实例。`active` 字段的值为 `true` ,并且 `sign_in_count` 的值为 `1` 。
< span class = "filename" > 文件名: src/main.rs< / span >
```rust
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-04/src/main.rs:here}}
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-04/src/main.rs:here}}
```
```
@ -44,13 +52,15 @@
### 使用字段初始化简写语法
### 使用字段初始化简写语法
因为示例 5-4 中的参数名与字段名都完全相同,我们可以使用 ** 字段初始化简写语法**( *field init shorthand*)来重写 `build_user` ,这样其行为与之前完全相同,不过无需重复 `email` 和 `username` 了,如示例 5-5 所示。
因为示例 5-4 中的参数名与字段名都完全相同,我们可以使用 ** 字段初始化简写语法**( *field init shorthand*)来重写 `build_user` ,这样其行为与之前完全相同,不过无需重复 `username` 和 `email` 了,如示例 5-5 所示。
< span class = "filename" > 文件名: src/main.rs< / span >
```rust
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-05/src/main.rs:here}}
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-05/src/main.rs:here}}
```
```
< span class = "caption" > 示例 5-5: `build_user` 函数使用了字段初始化简写语法,因为 ` email` 和 `username ` 参数与结构体字段同名</ span >
< span class = "caption" > 示例 5-5: `build_user` 函数使用了字段初始化简写语法,因为 ` username` 和 `email ` 参数与结构体字段同名</ span >
这里我们创建了一个新的 `User` 结构体实例,它有一个叫做 `email` 的字段。我们想要将 `email` 字段的值设置为 `build_user` 函数 `email` 参数的值。因为 `email` 字段与 `email` 参数有着相同的名称,则只需编写 `email` 而不是 `email: email` 。
这里我们创建了一个新的 `User` 结构体实例,它有一个叫做 `email` 的字段。我们想要将 `email` 字段的值设置为 `build_user` 函数 `email` 参数的值。因为 `email` 字段与 `email` 参数有着相同的名称,则只需编写 `email` 而不是 `email: email` 。
@ -60,6 +70,8 @@
首先,示例 5-6 展示了不使用更新语法时,如何在 `user2` 中创建一个新 `User` 实例。我们为 `email` 设置了新的值,其他值则使用了实例 5-2 中创建的 `user1` 中的同名值:
首先,示例 5-6 展示了不使用更新语法时,如何在 `user2` 中创建一个新 `User` 实例。我们为 `email` 设置了新的值,其他值则使用了实例 5-2 中创建的 `user1` 中的同名值:
< span class = "filename" > 文件名: src/main.rs< / span >
```rust
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-06/src/main.rs:here}}
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-06/src/main.rs:here}}
```
```
@ -68,6 +80,8 @@
使用结构体更新语法,我们可以通过更少的代码来达到相同的效果,如示例 5-7 所示。`..` 语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值。
使用结构体更新语法,我们可以通过更少的代码来达到相同的效果,如示例 5-7 所示。`..` 语法指定了剩余未显式设置值的字段应有与给定实例对应字段相同的值。
< span class = "filename" > 文件名: src/main.rs< / span >
```rust
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-07/src/main.rs:here}}
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/listing-05-07/src/main.rs:here}}
```
```
@ -76,7 +90,7 @@
示例 5-7 中的代码也在 `user2` 中创建了一个新实例,但该实例中 `email` 字段的值与 `user1` 不同,而 `username` 、 `active` 和 `sign_in_count` 字段的值与 `user1` 相同。`..user1` 必须放在最后,以指定其余的字段应从 `user1` 的相应字段中获取其值,但我们可以选择以任何顺序为任意字段指定值,而不用考虑结构体定义中字段的顺序。
示例 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] 部分讨论的行为同样适用。
### 使用没有命名字段的元组结构体来创建不同的类型
### 使用没有命名字段的元组结构体来创建不同的类型
@ -84,6 +98,8 @@
要定义元组结构体,以 `struct` 关键字和结构体名开头并后跟元组中的类型。例如,下面是两个分别叫做 `Color` 和 `Point` 元组结构体的定义和用法:
要定义元组结构体,以 `struct` 关键字和结构体名开头并后跟元组中的类型。例如,下面是两个分别叫做 `Color` 和 `Point` 元组结构体的定义和用法:
< span class = "filename" > 文件名: src/main.rs< / span >
```rust
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs}}
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-01-tuple-structs/src/main.rs}}
```
```
@ -94,6 +110,8 @@
我们也可以定义一个没有任何字段的结构体!它们被称为 ** 类单元结构体**( *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 >
```rust
```rust
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/src/main.rs}}
{{#rustdoc_include ../listings/ch05-using-structs-to-structure-related-data/no-listing-04-unit-like-structs/src/main.rs}}
```
```
@ -118,9 +136,9 @@
>
>
> fn main() {
> fn main() {
> let user1 = User {
> let user1 = User {
> email: "someone@example.com",
> username: "someusername123",
> active: true,
> active: true,
> username: "someusername123",
> email: "someone@example.com",
> sign_in_count: 1,
> sign_in_count: 1,
> };
> };
> }
> }