mirror of
https://github.com/KaiserY/trpl-zh-cn
synced 2024-11-09 08:51:18 +08:00
commit
46c17d4b28
@ -96,7 +96,7 @@ The value of x is: 5
|
||||
The value of y is: 6
|
||||
```
|
||||
|
||||
因为我们使用 `5` 作为 `x` 的值和 `6` 作为 `y` 的值来调用函数,这两个字符串和他们的值并被打印出来。
|
||||
因为我们使用 `5` 作为 `x` 的值和 `6` 作为 `y` 的值来调用函数,这两个字符串和他们的值被相应打印出来。
|
||||
|
||||
### 函数体
|
||||
|
||||
@ -104,7 +104,7 @@ The value of y is: 6
|
||||
|
||||
### 语句与表达式
|
||||
|
||||
我们已经用过语句与表达式了。**语句**(*Statements*)是执行一些操作但不返回值的指令。表达式(*Expressions*)计算并产生一个值。让我们看看一些例子:
|
||||
我们已经用过语句与表达式了。**语句**(*Statements*)是执行一些操作但不返回值的指令。表达式(*Expressions*)计算并产生一个值。让我们看一些例子:
|
||||
|
||||
使用 `let` 关键字创建变量并绑定一个值是一个语句。在列表 3-3 中,`let y = 6;` 是一个语句:
|
||||
|
||||
@ -146,7 +146,7 @@ error: expected expression, found statement (`let`)
|
||||
|
||||
`let y = 6` 语句并不返回值,所以并没有 `x` 可以绑定的值。这与其他语言不同,例如 C 和 Ruby,他们的赋值语句返回所赋的值。在这些语言中,可以这么写 `x = y = 6` 这样 `x` 和 `y` 的值都是 `6`;这在 Rust 中可不行。
|
||||
|
||||
表达式计算出一些值,而且他们组成了其余大部分你将会编写的 Rust 代码。考虑一个简单的数学运算,比如 `5 + 6`,这是一个表达式并计算出值 `11`。表达式可以是语句的一部分:在列表 3-3 中有这个语句 `let y = 6;`,`6` 是一个表达式它计算出的值是 `6`。函数调用是一个表达式。宏调用是一个表达式。我们用来创新建作用域的大括号(代码块),`{}`,也是一个表达式,例如:
|
||||
表达式计算出一些值,而且他们组成了其余大部分你将会编写的 Rust 代码。考虑一个简单的数学运算,比如 `5 + 6`,这是一个表达式并计算出值 `11`。表达式可以是语句的一部分:在列表 3-3 中有这个语句 `let y = 6;`,`6` 是一个表达式它计算出的值是 `6`。函数调用是一个表达式。宏调用是一个表达式。我们用来创建新作用域的大括号(代码块),`{}`,也是一个表达式,例如:
|
||||
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
|
@ -54,7 +54,7 @@ $ cargo run
|
||||
condition was false
|
||||
```
|
||||
|
||||
另外值得注意的是代码中的条件 **必须** 是 `bool`。如果像看看条件不是 `bool` 值时会发生什么,尝试运行如下代码:
|
||||
另外值得注意的是代码中的条件 **必须** 是 `bool`。如果想看看条件不是 `bool` 值时会发生什么,尝试运行如下代码:
|
||||
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
@ -202,7 +202,7 @@ error[E0308]: if and else have incompatible types
|
||||
|
||||
### 使用循环重复执行
|
||||
|
||||
多次执行同一段代码是很常用的。为了这个功能,Rust 提供了多种 **循环**(*loops*)。一个循环执行循环体中的代码直到结尾并紧接着从回到开头继续执行。为了实验一下循环,让我们创建一个叫做 *loops* 的新项目。
|
||||
多次执行同一段代码是很常用的。为了这个功能,Rust 提供了多种 **循环**(*loops*)。一个循环执行循环体中的代码直到结尾并紧接着回到开头继续执行。为了实验一下循环,让我们创建一个叫做 *loops* 的新项目。
|
||||
|
||||
Rust 有三种循环类型:`loop`、`while` 和 `for`。让我们每一个都试试。
|
||||
|
||||
|
@ -171,7 +171,7 @@ let s2 = s1;
|
||||
|
||||
之前,我们提到过当变量离开作用域后 Rust 自动调用 `drop` 函数并清理变量的堆内存。不过图 4-4 展示了两个数据指针指向了同一位置。这就有了一个问题:当 `s2` 和 `s1` 离开作用域,他们都会尝试释放相同的内存。这是一个叫做 *double free* 的错误,也是之前提到过的内存安全性 bug 之一。两次释放(相同)内存会导致内存污染,它可能会导致潜在的安全漏洞。
|
||||
|
||||
为了确保内存安全,这种场景下 Rust 的处理有另一个细节值得注意。与其尝试拷贝被分配的内存,Rust 则认为 `s1` 不再有效,因此 Rust 不需要在 `s1` 离开作用域后清理任何东西。看看在 `s2` 被创建之后尝试使用 `s1` 会发生生么:
|
||||
为了确保内存安全,这种场景下 Rust 的处理有另一个细节值得注意。与其尝试拷贝被分配的内存,Rust 则认为 `s1` 不再有效,因此 Rust 不需要在 `s1` 离开作用域后清理任何东西。看看在 `s2` 被创建之后尝试使用 `s1` 会发生什么:
|
||||
|
||||
```rust,ignore
|
||||
let s1 = String::from("hello");
|
||||
@ -195,7 +195,7 @@ error[E0382]: use of moved value: `s1`
|
||||
which does not implement the `Copy` trait
|
||||
```
|
||||
|
||||
如果你在其他语言中听说过术语 “浅拷贝”(“shallow copy”)和 “深拷贝”(“deep copy”),那么拷贝指针、长度和容量而不拷贝数据可能听起来像浅拷贝。不过因为 Rust 同时使第一个变量无效化了,这个操作被称为 **移动**(*move*),而不是浅拷贝。上面的例子可以解读为 `s1` 被 **移动** 到了 `s2` 中。那么具体发生了什么如图 4-6 所示。
|
||||
如果你在其他语言中听说过术语 “浅拷贝”(“shallow copy”)和 “深拷贝”(“deep copy”),那么拷贝指针、长度和容量而不拷贝数据可能听起来像浅拷贝。不过因为 Rust 同时使第一个变量无效化了,这个操作被称为 **移动**(*move*),而不是浅拷贝。上面的例子可以解读为 `s1` 被 **移动** 到了 `s2` 中。那么具体发生了什么,如图 4-6 所示。
|
||||
|
||||
<img alt="s1 moved to s2" src="img/trpl04-04.svg" class="center" style="width: 50%;" />
|
||||
|
||||
|
@ -4,9 +4,9 @@
|
||||
> <br>
|
||||
> commit 56352c28cf3fe0402fa5a7cba73890e314d720eb
|
||||
|
||||
我们在第三章讨论过,结构体与元组类似。就像元组,结构体的每一部分可以是不同类型。不同于元组,需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字使得结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
|
||||
我们在第三章讨论过,结构体与元组类似。就像元组,结构体的每一部分可以是不同类型。不同于元组,结构体需要命名各部分数据以便能清楚的表明其值的意义。由于有了这些名字使得结构体比元组更灵活:不需要依赖顺序来指定或访问实例中的值。
|
||||
|
||||
为了定义结构体,通过 `struct` 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字,他们被称作 **字段**(*field*),并定义字段类型。例如,示例 5-1 展示了一个储存用户账号信息的结构体:
|
||||
定义结构体,需要使用 `struct` 关键字并为整个结构体提供一个名字。结构体的名字需要描述它所组合的数据的意义。接着,在大括号中,定义每一部分数据的名字,他们被称作 **字段**(*field*),并定义字段类型。例如,示例 5-1 展示了一个储存用户账号信息的结构体:
|
||||
|
||||
```rust
|
||||
struct User {
|
||||
@ -178,7 +178,7 @@ let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
```
|
||||
|
||||
注意 `black` 和 `origin` 变量有不同的类型,因为他们是不同的元组结构体的实例。我们定义的每一个结构体有着自己的类型,即使结构体中的字段有相同的类型。在其他方面,元组结构体类似我们在第三章提到的元组。
|
||||
注意 `black` 和 `origin` 变量是不同的类型,因为他们是不同的元组结构体的实例。我们定义的每一个结构体有着自己的类型,即使结构体中的字段有相同的类型。在其他方面,元组结构体类似我们在第三章提到的元组。
|
||||
|
||||
### 没有任何字段的类单元结构体
|
||||
|
||||
|
@ -71,7 +71,7 @@ fn area(dimensions: (u32, u32)) -> u32 {
|
||||
|
||||
### 使用结构体重构:增加更多意义
|
||||
|
||||
现在引入结构体的时候了。我们可以将元组转换为一个有整体名称而且每个部分也有对应名字的数据类型,如示例 5-10 所示:
|
||||
现在是引入结构体的时候了。我们可以将元组转换为一个有整体名称而且每个部分也有对应名字的数据类型,如示例 5-10 所示:
|
||||
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
@ -174,7 +174,7 @@ fn main() {
|
||||
|
||||
<span class="caption">示例 5-12:增加注解来导出 `Debug` trait </span>
|
||||
|
||||
此时此刻运行程序,运行这个程序,不会有任何错误并会出现如下输出:
|
||||
现在我们再运行这个程序时,不会有任何错误并会出现如下输出:
|
||||
|
||||
```text
|
||||
rect1 is Rectangle { length: 50, width: 30 }
|
||||
|
Loading…
Reference in New Issue
Block a user