mirror of
https://github.com/KaiserY/trpl-zh-cn
synced 2024-11-09 08:51:18 +08:00
check ch03-05
This commit is contained in:
parent
2cbb16c296
commit
9eb6f98334
@ -2,19 +2,19 @@
|
||||
|
||||
> [ch03-02-data-types.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch03-02-data-types.md)
|
||||
> <br>
|
||||
> commit fe4833a8ef2853c55424e7747a4ef8dd64c35b32
|
||||
> commit 1d4f34661d4b13ecda4885d496e1b84cdbcbed31
|
||||
|
||||
在 Rust 中,任何值都属于一种明确的**类型**(*type*),声明它被指定了何种数据,以便明确其处理方式。我们将分两部分探讨一些内建类型:标量(scalar)和复合(compound)。
|
||||
在 Rust 中,任何值都属于一种明确的 **类型**(*type*),这告诉了 Rust 它被指定了何种数据,以便明确其处理方式。我们将分两部分探讨一些内建类型:标量(scalar)和复合(compound)。
|
||||
|
||||
Rust 是**静态类型**(*statically typed*)语言,也就是说在编译时就需要知道所有变量的类型,这一认知将贯穿整个章节,请在头脑中明确。通过值的形式及其使用方式,编译器通常可以推断出我们想要用的类型。多种类型均有可能时,比如第二章中使用 `parse` 将 `String` 转换为数字,必须增加类型注解,像这样:
|
||||
Rust 是 **静态类型**(*statically typed*)语言,也就是说在编译时就必须知道所有变量的类型,这一认知将贯穿整个章节,请在头脑中明确。通过值的形式及其使用方式,编译器通常可以推断出我们想要用的类型。多种类型均有可能时,比如第二章中使用 `parse` 将 `String` 转换为数字时,必须增加类型注解,像这样:
|
||||
|
||||
```rust
|
||||
let guess: u32 = "42".parse().expect("Not a number!");
|
||||
```
|
||||
|
||||
如果不添加类型注解,Rust 会显示如下错误。这说明编译器需要更多信息,来了解我们想要的类型:
|
||||
这里如果不添加类型注解,Rust 会显示如下错误,这说明编译器需要更多信息,来了解我们想要的类型:
|
||||
|
||||
```
|
||||
```text
|
||||
error[E0282]: unable to infer enough type information about `_`
|
||||
--> src/main.rs:2:9
|
||||
|
|
||||
@ -28,15 +28,15 @@ error[E0282]: unable to infer enough type information about `_`
|
||||
|
||||
### 标量类型
|
||||
|
||||
**标量**类型代表一个单独的值。Rust 有四种基本的标量类型:整型、浮点型、布尔类型和字符类型。你可能在其他语言中见过他们,不过让我们深入了解他们在 Rust 中时如何工作的。
|
||||
**标量**(*scalar*)类型代表一个单独的值。Rust 有四种基本的标量类型:整型、浮点型、布尔类型和字符类型。你可能在其他语言中见过他们,不过让我们深入了解他们在 Rust 中时如何工作的。
|
||||
|
||||
#### 整型
|
||||
|
||||
**整数** 是一个没有小数部分的数字。我们在这一章的前面使用过 `i32` 类型。该类型声明指示,i32 关联的值应该是一个占据 32 比特位的有符号整数(因为这个`i`,与`u`代表的无符号相对)。表格 3-1 展示了 Rust 内建的整数类型。每一种变体的有符号和无符号列(例如,*i32*)可以用来声明对应的整数值。
|
||||
|
||||
<span class="caption">Table 3-1: Integer Types in Rust</span>
|
||||
<span class="caption">表格 3-1: Rust 中的整型</span>
|
||||
|
||||
| Length | Signed | Unsigned |
|
||||
| 长度 | 有符号 | 无符号 |
|
||||
|--------|--------|----------|
|
||||
| 8-bit | i8 | u8 |
|
||||
| 16-bit | i16 | u16 |
|
||||
@ -50,11 +50,11 @@ error[E0282]: unable to infer enough type information about `_`
|
||||
|
||||
另外,`isize` 和 `usize` 类型依赖运行程序的计算机架构:64 位架构上他们是 64 位的, 32 位架构上他们是 32 位的。
|
||||
|
||||
可以使用表格 3-2 中的任何一种形式编写数字字面值。除字节以外的其它字面值允许使用类型后缀,例如 `57u8`,允许使用 `_` 做为分隔符以方便读数,例如 `1_000` (分隔符的数量与位置并不影响实际的数字)。
|
||||
可以使用表格 3-2 中的任何一种形式编写数字字面值。注意除字节以外的其它字面值允许使用类型后缀,例如 `57u8`,允许使用 `_` 做为分隔符以方便读数。
|
||||
|
||||
<span class="caption">Table 3-2: Integer Literals in Rust</span>
|
||||
<span class="caption">表格 3-2: RUst 中的整型字面值</span>
|
||||
|
||||
| Number literals | Example |
|
||||
| 数字字面值 | 例子 |
|
||||
|------------------|---------------|
|
||||
| Decimal | `98_222` |
|
||||
| Hex | `0xff` |
|
||||
@ -62,15 +62,15 @@ error[E0282]: unable to infer enough type information about `_`
|
||||
| Binary | `0b1111_0000` |
|
||||
| Byte (`u8` only) | `b'A'` |
|
||||
|
||||
那么该使用哪种类型的数字呢?如果拿不定主意,Rust 的默认类型通常就很好,数字类型默认是 `i32`:它通常是最快的,甚至在 64 位系统上也是。`isize` 或 `usize` 的主要作为集合的索引。
|
||||
那么该使用哪种类型的数字呢?如果拿不定主意,Rust 的默认类型通常就很好,数字类型默认是 `i32`:它通常是最快的,甚至在 64 位系统上也是。`isize` 或 `usize` 主要作为集合的索引。
|
||||
|
||||
#### 浮点型
|
||||
|
||||
Rust 同样有两个主要的**浮点数**类型,`f32` 和 `f64`,它们是带小数点的数字,分别占 32 位和 64 位比特。默认类型是 `f64`,因为它与 `f32` 速度差不多,然而精度更高。在 32 位系统上也能够使用 `f64`,不过比使用 `f32` 要慢。多数情况下,以潜在的性能损耗换取更高的精度是合理的;如果觉得浮点数的大小是个麻烦,你应该以性能测试作为决策依据。
|
||||
Rust 同样有两个主要的 **浮点数**(*floating-point numbers*)类型,`f32` 和 `f64`,它们是带小数点的数字,分别占 32 位和 64 位比特。默认类型是 `f64`,因为它与 `f32` 速度差不多,然而精度更高。在 32 位系统上也能够使用 `f64`,不过比使用 `f32` 要慢。多数情况下,一开始以潜在的性能损耗换取更高的精度是合理的;如果觉得浮点数的大小是个麻烦,你应该以性能测试作为决策依据。
|
||||
|
||||
这是一个展示浮点数的实例:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -86,7 +86,7 @@ fn main() {
|
||||
|
||||
Rust 支持所有数字类型常见的基本数学运算操作:加法、减法、乘法、除法以及余数。如下代码展示了如何使用一个 `let` 语句来使用他们:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -113,8 +113,7 @@ fn main() {
|
||||
|
||||
正如其他大部分编程语言一样,Rust 中的布尔类型有两个可能的值:`true` 和 `false`。Rust 中的布尔类型使用 `bool` 表示。例如:
|
||||
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -124,13 +123,13 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
使用布尔值的主要场景是条件表达式,例如`if`。在“控制流”(“Control Flow”)部分将讲到`if`表达式在 Rust 中如何工作。
|
||||
使用布尔值的主要场景是条件表达式,例如 `if` 表达式。在 “控制流”(“Control Flow”)部分将讲到`if`表达式在 Rust 中如何工作。
|
||||
|
||||
#### 字符类型
|
||||
|
||||
目前为止只使用到了数字,不过 Rust 也支持字符。Rust 的 `char` 类型是大部分语言中基本字母字符类型,如下代码展示了如何使用它:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -140,11 +139,11 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Rust 的`char`类型代表了一个 Unicode 变量值(Unicode Scalar Value),这意味着它可以比 ASCII 表示更多内容。拼音字母(Accented letters),中文/日文/汉语等象形文字,emoji(絵文字)以及零长度的空白字符对于 Rust `char`类型都是有效的。Unicode 标量值包含从 `U+0000` 到 `U+D7FF` 和 `U+E000` 到 `U+10FFFF` 之间的值。不过,“字符”并不是一个 Unicode 中的概念,所以人直觉上的“字符”可能与 Rust 中的`char`并不符合。第八章的“字符串”部分将详细讨论这个主题。
|
||||
Rust 的 `char` 类型代表了一个 Unicode 标量值(Unicode Scalar Value),这意味着它可以比 ASCII 表示更多内容。拼音字母(Accented letters),中文/日文/汉语等象形文字,emoji(絵文字)以及零长度的空白字符对于 Rust `char`类型都是有效的。Unicode 标量值包含从 `U+0000` 到 `U+D7FF` 和 `U+E000` 到 `U+10FFFF` 之间的值。不过,“字符” 并不是一个 Unicode 中的概念,所以人直觉上的 “字符” 可能与 Rust 中的 `char` 并不符合。第八章的 “字符串” 部分将详细讨论这个主题。
|
||||
|
||||
### 复合类型
|
||||
|
||||
**复合类型**可以将多个其他类型的值组合成一个类型。Rust 有两个原生的复合类型:元组(tuple)和数组(array)。
|
||||
**复合类型**(*Compound types*)可以将多个其他类型的值组合成一个类型。Rust 有两个原生的复合类型:元组(tuple)和数组(array)。
|
||||
|
||||
#### 将值组合进元组
|
||||
|
||||
@ -152,7 +151,7 @@ Rust 的`char`类型代表了一个 Unicode 变量值(Unicode Scalar Value)
|
||||
|
||||
我们使用一个括号中的逗号分隔的值列表来创建一个元组。元组中的每一个位置都有一个类型,而且这些不同值的类型也不必是相同的。这个例子中使用了额外的可选类型注解:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -162,7 +161,7 @@ fn main() {
|
||||
|
||||
`tup` 变量绑定了整个元组,因为元组被认为是一个单独的复合元素。为了从元组中获取单个的值,可以使用模式匹配(pattern matching)来解构(destructure)元组,像这样:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -178,7 +177,7 @@ fn main() {
|
||||
|
||||
除了使用模式匹配解构之外,也可以使用点号(`.`)后跟值的索引来直接访问他们。例如:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -200,7 +199,7 @@ fn main() {
|
||||
|
||||
Rust 中数组的值位于中括号中的逗号分隔的列表中:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -208,7 +207,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
数组在想要在栈(stack)而不是在堆(heap)上为数据分配空间时十分有用(第四章将讨论栈与堆的更多内容),或者是想要确保总是有固定数量的元素时。虽然它并不如 vector 类型那么灵活。vector 类型是标准库提供的一个**允许**增长和缩小长度的类似数组的集合类型。当不确定是应该使用数组还是 vector 的时候,你可能应该使用 vector:第八章会详细讨论 vector。
|
||||
数组在需要在栈(stack)而不是在堆(heap)上为数据分配空间时(第四章将讨论栈与堆的更多内容),或者是想要确保总是有固定数量的元素时十分有用。虽然它并不如 vector 类型那么灵活。vector 类型是标准库提供的一个 **允许** 增长和缩小长度的类似数组的集合类型。当不确定是应该使用数组还是 vector 的时候,你可能应该使用 vector:第八章会详细讨论 vector。
|
||||
|
||||
一个你可能想要使用数组而不是 vector 的例子是当程序需要知道一年中月份的名字时。程序不大可能回去增加或减少月份,这时你可以使用数组因为我们知道它总是含有 12 个元素:
|
||||
|
||||
@ -221,7 +220,7 @@ let months = ["January", "February", "March", "April", "May", "June", "July",
|
||||
|
||||
数组是一整块分配在栈上的内存。可以使用索引来访问数组的元素,像这样:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -238,13 +237,14 @@ fn main() {
|
||||
|
||||
如果我们访问数组结尾之后的元素会发生什么呢?比如我们将上面的例子改为如下:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
let a = [1, 2, 3, 4, 5];
|
||||
let index = 10;
|
||||
|
||||
let element = a[10];
|
||||
let element = a[index];
|
||||
|
||||
println!("The value of element is: {}", element);
|
||||
}
|
||||
@ -252,14 +252,13 @@ fn main() {
|
||||
|
||||
使用 `cargo run` 运行代码后会产生如下结果:
|
||||
|
||||
```
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling arrays v0.1.0 (file:///projects/arrays)
|
||||
Running `target/debug/arrays`
|
||||
thread '<main>' panicked at 'index out of bounds: the len is 5 but the index is
|
||||
10', src/main.rs:4
|
||||
10', src/main.rs:6
|
||||
note: Run with `RUST_BACKTRACE=1` for a backtrace.
|
||||
error: Process didn't exit successfully: `target/debug/arrays` (exit code: 101)
|
||||
```
|
||||
|
||||
编译并没有产生任何错误,不过程序会导致一个 **运行时**(*runtime*)错误并且不会成功退出。当尝试用索引访问一个元素时,Rust 会检查指定的索引是否小于数组的长度。如果索引超出了数组长度,Rust 会 *panic*,这是 Rust 中的术语,它用于程序因为错误而退出的情况。
|
||||
|
@ -2,13 +2,13 @@
|
||||
|
||||
> [ch03-03-how-functions-work.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch03-03-how-functions-work.md)
|
||||
> <br>
|
||||
> commit 04aa3a45eb72855b34213703718f50a12a3eeec8
|
||||
> commit d06a6a181fd61704cbf7feb55bc61d518c6469f9
|
||||
|
||||
函数在 Rust 代码中应用广泛。你已经见过一个语言中最重要的函数:`main`函数,它时很多程序的入口点。你也见过了`fn`关键字,它用来声明新函数。
|
||||
函数在 Rust 代码中应用广泛。你已经见过一个语言中最重要的函数:`main` 函数,它是很多程序的入口点。你也见过了 `fn` 关键字,它用来声明新函数。
|
||||
|
||||
Rust 代码使用 *snake case* 作为函数和变量名称的规范风格。在 snake case 中,所有字母都是小写并使用下划线分隔单词。这里是一个函数定义程序的例子:
|
||||
Rust 代码使用 *snake case* 作为函数和变量名称的规范风格。在 snake case 中,所有字母都是小写并使用下划线分隔单词。这里是一个包含函数定义的程序的例子:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -24,11 +24,11 @@ fn another_function() {
|
||||
|
||||
Rust 中的函数定义以 `fn` 开始并在函数名后跟一对括号。大括号告诉编译器哪里是函数体的开始和结尾。
|
||||
|
||||
可以使用定义过的函数名后跟括号来调用任意函数。因为`another_function`已经在程序中定义过了,它可以在`main`函数中被调用。注意,源码中`another_function`在`main`函数*之后*被定义;也可以在其之前定义。Rust 不关心函数定义于何处,只要他们被定义了。
|
||||
可以使用定义过的函数名后跟括号来调用任意函数。因为 `another_function` 已经在程序中定义过了,它可以在 `main` 函数中被调用。注意,源码中 `another_function` 在 `main` 函数 **之后** 被定义;也可以在其之前定义。Rust 不关心函数定义于何处,只要他们被定义了。
|
||||
|
||||
让我们开始一个叫做 *functions* 的新二进制项目来进一步探索函数。将上面的 `another_function` 例子写入 *src/main.rs* 中并运行。你应该会看到如下输出:
|
||||
|
||||
```
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling functions v0.1.0 (file:///projects/functions)
|
||||
Running `target/debug/functions`
|
||||
@ -40,12 +40,11 @@ Another function.
|
||||
|
||||
### 函数参数
|
||||
|
||||
函数也可以被定义为拥有**参数**(*parameters*),他们是作为函数签名一部分的特殊变量。当函数拥有参数,可以为这些参数提供具体的值。技术上讲,这些具体值被称为参数( *arguments*),不过通常的习惯是倾向于在函数定义中的变量和调用函数时传递的具体值都可以用“parameter”和“argument”而不加区别。
|
||||
函数也可以被定义为拥有 **参数**(*parameters*),他们是作为函数签名一部分的特殊变量。当函数拥有参数时,可以为这些参数提供具体的值。技术上讲,这些具体值被称为参数( *arguments*),不过通常的习惯是倾向于在函数定义中的变量和调用函数时传递的具体值都可以用 “parameter” 和 “argument” 而不加区别。
|
||||
|
||||
如下被重写的 `another_function` 版本展示了 Rust 中参数是什么样的:
|
||||
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -59,7 +58,7 @@ fn another_function(x: i32) {
|
||||
|
||||
尝试运行程序,将会得到如下输出:
|
||||
|
||||
```sh
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling functions v0.1.0 (file:///projects/functions)
|
||||
Running `target/debug/functions`
|
||||
@ -72,7 +71,7 @@ The value of x is: 5
|
||||
|
||||
当一个函数有多个参数时,使用逗号隔开他们,像这样:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -89,7 +88,7 @@ fn another_function(x: i32, y: i32) {
|
||||
|
||||
尝试运行代码。使用上面的例子替换当前 *function* 项目的 *src/main.rs* 文件,并 `cargo run` 运行它:
|
||||
|
||||
```sh
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling functions v0.1.0 (file:///projects/functions)
|
||||
Running `target/debug/functions`
|
||||
@ -109,7 +108,7 @@ The value of y is: 6
|
||||
|
||||
使用 `let` 关键字创建变量并绑定一个值是一个语句。在列表 3-3 中,`let y = 6;` 是一个语句:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -117,7 +116,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 3-3: A `main` function declaration containing one statement.</span>
|
||||
<span class="caption">列表 3-3:包含一个语句的 `main` 函数定义</span>
|
||||
|
||||
函数定义也是语句;上面整个例子本身就是一个语句。
|
||||
|
||||
@ -133,7 +132,7 @@ fn main() {
|
||||
|
||||
当运行这个程序,会得到如下错误:
|
||||
|
||||
```
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling functions v0.1.0 (file:///projects/functions)
|
||||
error: expected expression, found statement (`let`)
|
||||
@ -149,7 +148,7 @@ error: expected expression, found statement (`let`)
|
||||
|
||||
表达式计算出一些值,而且他们组成了其余大部分你将会编写的 Rust 代码。考虑一个简单的数学运算,比如 `5 + 6`,这是一个表达式并计算出值 `11`。表达式可以是语句的一部分:在列表 3-3 中有这个语句 `let y = 6;`,`6` 是一个表达式它计算出的值是 `6`。函数调用是一个表达式。宏调用是一个表达式。我们用来创新建作用域的大括号(代码块),`{}`,也是一个表达式,例如:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -179,7 +178,7 @@ fn main() {
|
||||
|
||||
可以向调用它的代码返回值。并不对返回值命名,不过会在一个箭头(`->`)后声明它的类型。在 Rust 中,函数的返回值等同于函数体最后一个表达式的值。这是一个有返回值的函数的例子:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn five() -> i32 {
|
||||
@ -193,9 +192,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
在函数`five`中并没有函数调用、宏、甚至也没有`let`语句————只有数字`5`它自己。这在 Rust 中是一个完全有效的函数。注意函数的返回值类型也被指定了,就是`-> i32`。尝试运行代码;输出应该看起来像这样:
|
||||
在函数 `five` 中并没有函数调用、宏、甚至也没有 `let` 语句————只有数字 `5` 自身。这在 Rust 中是一个完全有效的函数。注意函数的返回值类型也被指定了,就是 `-> i32`。尝试运行代码;输出应该看起来像这样:
|
||||
|
||||
```
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling functions v0.1.0 (file:///projects/functions)
|
||||
Running `target/debug/functions`
|
||||
@ -210,7 +209,7 @@ let x = 5;
|
||||
|
||||
其次,函数 `five` 没有参数并定义了返回值类型,不过函数体只有单单一个 `5` 也没有分号,因为这是我们想要返回值的表达式。让我们看看另一个例子:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -226,7 +225,7 @@ fn plus_one(x: i32) -> i32 {
|
||||
|
||||
运行代码会打印出 `The value of x is: 6`。如果在包含 `x + 1` 的那一行的结尾加上一个分号,把它从表达式变成语句后会怎样呢?
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
@ -242,15 +241,15 @@ fn plus_one(x: i32) -> i32 {
|
||||
|
||||
运行代码会产生一个错误,如下:
|
||||
|
||||
```
|
||||
```text
|
||||
error[E0308]: mismatched types
|
||||
--> src/main.rs:7:28
|
||||
|
|
||||
7 | fn plus_one(x: i32) -> i32 {
|
||||
| ____________________________^ starting here...
|
||||
| ____________________________^
|
||||
8 | | x + 1;
|
||||
9 | | }
|
||||
| |_^ ...ending here: expected i32, found ()
|
||||
| |_^ expected i32, found ()
|
||||
|
|
||||
= note: expected type `i32`
|
||||
found type `()`
|
||||
@ -261,4 +260,4 @@ help: consider removing this semicolon:
|
||||
| ^
|
||||
```
|
||||
|
||||
主要的错误信息,“mismatched types,”(类型不匹配),揭示了代码的核心问题。函数`plus_one`的定义说明它要返回一个`i32`,不过语句并不返回一个值,这由那个空元组`()`表明。因此,这个函数返回了空元组`()`(译者注:原文说此函数没有返回任何值,可能有误),这与函数定义相矛盾并导致一个错误。在输出中,Rust 提供了一个可能会对修正问题有帮助的信息:它建议去掉分号,这会修复这个错误。
|
||||
主要的错误信息,“mismatched types,”(类型不匹配),揭示了代码的核心问题。函数`plus_one` 的定义说明它要返回一个 `i32`,不过语句并不返回一个值,这由那个空元组 `()` 表明。因此,这个函数返回了空元组 `()`,这与函数定义相矛盾并导致一个错误。在输出中,Rust 提供了一个可能会对修正问题有帮助的信息:它建议去掉分号,这会修复这个错误。
|
@ -2,7 +2,7 @@
|
||||
|
||||
> [ch03-04-comments.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch03-04-comments.md)
|
||||
> <br>
|
||||
> commit 4f2dc564851dc04b271a2260c834643dfd86c724
|
||||
> commit d06a6a181fd61704cbf7feb55bc61d518c6469f9
|
||||
|
||||
所有编程语言都力求使他们的代码易于理解,不过有时需要提供额外的解释。在这种情况下,程序员在源码中留下记录,或者 **注释**(*comments*),编译器会忽略他们不过其他阅读代码的人可能会用得上。
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
|
||||
注释也可以在放在包含代码的行的末尾:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -32,7 +32,7 @@ fn main() {
|
||||
|
||||
不过你会经常看到他们被以这种格式使用,也就是位于它所解释的代码行的上面一行:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
> [ch03-05-control-flow.md](https://github.com/rust-lang/book/blob/master/src/ch03-05-control-flow.md)
|
||||
> <br>
|
||||
> commit 04aa3a45eb72855b34213703718f50a12a3eeec8
|
||||
> commit 2e269ff82193fd65df8a87c06561d74b51ac02f7
|
||||
|
||||
通过条件是不是真来决定是否某些代码,或者根据条件是否为真来重复运行一段代码是大部分编程语言的基本组成部分。Rust 代码中最常见的用来控制执行流的结构是`if`表达式和循环。
|
||||
通过条件是不是为真来决定是否执行某些代码,或者根据条件是否为真来重复运行一段代码是大部分编程语言的基本组成部分。Rust 代码中最常见的用来控制执行流的结构是 `if` 表达式和循环。
|
||||
|
||||
### `if` 表达式
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
|
||||
在 *projects* 目录创建一个叫做 *branches* 的新项目来学习 `if` 表达式。在 *src/main.rs* 文件中,输入如下内容:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -32,7 +32,7 @@ fn main() {
|
||||
|
||||
尝试运行代码,应该能看到如下输出:
|
||||
|
||||
```
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling branches v0.1.0 (file:///projects/branches)
|
||||
Running `target/debug/branches`
|
||||
@ -47,7 +47,7 @@ let number = 7;
|
||||
|
||||
再次运行程序并查看输出:
|
||||
|
||||
```
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling branches v0.1.0 (file:///projects/branches)
|
||||
Running `target/debug/branches`
|
||||
@ -56,7 +56,7 @@ condition was false
|
||||
|
||||
另外值得注意的是代码中的条件 **必须** 是 `bool`。如果像看看条件不是 `bool` 值时会发生什么,尝试运行如下代码:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
@ -70,7 +70,7 @@ fn main() {
|
||||
|
||||
这里 `if` 条件的值是 `3`,Rust 抛出了一个错误:
|
||||
|
||||
```
|
||||
```text
|
||||
error[E0308]: mismatched types
|
||||
--> src/main.rs:4:8
|
||||
|
|
||||
@ -83,7 +83,7 @@ error[E0308]: mismatched types
|
||||
|
||||
这个错误表明 Rust 期望一个 `bool` 不过却得到了一个整型。Rust 并不会尝试自动地将非布尔值转换为布尔值,不像例如 Ruby 和 JavaScript 这样的语言。必须总是显式地使用 `boolean` 作为 `if` 的条件。例如如果想 要`if` 代码块只在一个数字不等于 `0` 时执行,可以把 `if` 表达式修改为如下:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -101,7 +101,7 @@ fn main() {
|
||||
|
||||
可以将 `else if` 表达式与 `if` 和 `else` 组合来实现多重条件。例如:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -121,7 +121,7 @@ fn main() {
|
||||
|
||||
这个程序有四个可能的执行路径。运行后应该能看到如下输出:
|
||||
|
||||
```
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling branches v0.1.0 (file:///projects/branches)
|
||||
Running `target/debug/branches`
|
||||
@ -136,7 +136,7 @@ number is divisible by 3
|
||||
|
||||
因为 `if` 是一个表达式,我们可以在 `let` 语句的右侧使用它,例如在列表 3-4 中:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -151,12 +151,11 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 3-4: Assigning the result of an `if` expression
|
||||
to a variable</span>
|
||||
<span class="caption">列表 3-4:将 `if` 的返回值赋值给一个变量</span>
|
||||
|
||||
`number` 变量将会绑定到基于 `if` 表达式结果的值。运行这段代码看看会出现什么:
|
||||
|
||||
```
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling branches v0.1.0 (file:///projects/branches)
|
||||
Running `target/debug/branches`
|
||||
@ -165,7 +164,7 @@ The value of number is: 5
|
||||
|
||||
还记得代码块的值是其最后一个表达式的值,以及数字本身也是一个表达式吗。在这个例子中,整个 `if` 表达式的值依赖哪个代码块被执行。这意味着 `if` 的每个分支的可能的返回值都必须是相同类型;在列表 3-4 中,`if` 分支和 `else` 分支的结果都是 `i32` 整型。不过如果像下面的例子那样这些类型并不匹配会怎么样呢?
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
@ -183,17 +182,17 @@ fn main() {
|
||||
|
||||
当运行这段代码,会得到一个错误。`if` 和 `else` 分支的值类型是不相容的,同时 Rust 也准确地表明了在程序中的何处发现的这个问题:
|
||||
|
||||
```
|
||||
```text
|
||||
error[E0308]: if and else have incompatible types
|
||||
--> src/main.rs:4:18
|
||||
|
|
||||
4 | let number = if condition {
|
||||
| __________________^ starting here...
|
||||
| __________________^
|
||||
5 | | 5
|
||||
6 | | } else {
|
||||
7 | | "six"
|
||||
8 | | };
|
||||
| |_____^ ...ending here: expected integral variable, found reference
|
||||
| |_____^ expected integral variable, found reference
|
||||
|
|
||||
= note: expected type `{integer}`
|
||||
found type `&'static str`
|
||||
@ -203,7 +202,7 @@ error[E0308]: if and else have incompatible types
|
||||
|
||||
### 使用循环重复执行
|
||||
|
||||
多次执行一段代码是很常用的。为了这个功能,Rust 提供了多种**循环**(*loops*)。一个循环执行循环体中的代码直到结尾并紧接着从回到开头继续执行。为了实验一下循环,让我们创建一个叫做 *loops* 的新项目。
|
||||
多次执行同一段代码是很常用的。为了这个功能,Rust 提供了多种 **循环**(*loops*)。一个循环执行循环体中的代码直到结尾并紧接着从回到开头继续执行。为了实验一下循环,让我们创建一个叫做 *loops* 的新项目。
|
||||
|
||||
Rust 有三种循环类型:`loop`、`while` 和 `for`。让我们每一个都试试。
|
||||
|
||||
@ -213,7 +212,7 @@ Rust 有三种循环类型:`loop`、`while`和`for`。让我们每一个都试
|
||||
|
||||
作为一个例子,将 *loops* 目录中的 *src/main.rs* 文件修改为如下:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust,ignore
|
||||
fn main() {
|
||||
@ -223,9 +222,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
当执行这个程序,我们会看到`again!`被连续的打印直到我们手动停止程序.大部分终端都支持一个键盘快捷键,ctrl-C,来终止一个陷入无限循环的程序。尝试一下:
|
||||
当执行这个程序,我们会看到 `again!` 被连续的打印直到我们手动停止程序。大部分终端都支持一个键盘快捷键,<span class="keystroke">ctrl-C</span>,来终止一个陷入无限循环的程序。尝试一下:
|
||||
|
||||
```sh
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling loops v0.1.0 (file:///projects/loops)
|
||||
Running `target/debug/loops`
|
||||
@ -236,7 +235,7 @@ again!
|
||||
^Cagain!
|
||||
```
|
||||
|
||||
符号`^C`代表你在这按下了 ctrl-C。在`^C`之后你可能看到`again!`也可能看不到,这依赖于在接收到终止信号时代码执行到了循环的何处。
|
||||
符号 `^C` 代表你在这按下了<span class="keystroke">ctrl-C</span>。在 `^C` 之后你可能看到 `again!` 也可能看不到,这依赖于在接收到终止信号时代码执行到了循环的何处。
|
||||
|
||||
幸运的是,Rust 提供了另一个更可靠的方式来退出循环。可以使用 `break` 关键字来告诉程序何时停止执行循环。还记得我们在第二章猜猜看游戏的 “猜测正确后退出” 部分使用过它来在用户猜对数字赢得游戏后退出程序吗。
|
||||
|
||||
@ -246,7 +245,7 @@ again!
|
||||
|
||||
然而,这个模式太常见了以至于 Rust 为此提供了一个内建的语言结构,它被称为 `while` 循环。下面的例子使用了 `while`:程序循环三次,每次数字都减一。接着,在循环之后,打印出另一个信息并退出:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -266,9 +265,9 @@ fn main() {
|
||||
|
||||
#### 使用 `for` 遍历集合
|
||||
|
||||
可以使用`while`结构来遍历一个元素集合,比如数组。例如:
|
||||
可以使用 `while` 结构来遍历一个元素集合,比如数组。如下:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -283,12 +282,11 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 3-5: Looping through each element of a collection
|
||||
using a `while` loop</span>
|
||||
<span class="caption">列表 3-5:使用 `while` 循环遍历集合中的每一个元素</span>
|
||||
|
||||
这里代码对数组中的元素进行计数。它从索引 `0` 开始,并接着循环直到遇到数组的最后一个索引(这时,`index < 5` 不再为真)。运行这段代码会打印出数组中的每一个元素:
|
||||
|
||||
```sh
|
||||
```text
|
||||
$ cargo run
|
||||
Compiling loops v0.1.0 (file:///projects/loops)
|
||||
Running `target/debug/loops`
|
||||
@ -303,9 +301,9 @@ the value is: 50
|
||||
|
||||
不过这个过程是容易出错的;如果索引长度不正确会导致程序 panic。这也使程序更慢,因为编译器增加了运行时代码来对每次循环的每个元素进行条件检查。
|
||||
|
||||
可以使用`for`循环来对一个集合的每个元素执行一些代码,来作为一个更有效率替代。`for`循环看起来像这样:
|
||||
可以使用 `for` 循环来对一个集合的每个元素执行一些代码,来作为一个更有效率的替代。`for` 循环看起来像这样:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -317,10 +315,9 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
<span class="caption">Listing 3-6: Looping through each element of a collection
|
||||
using a `for` loop</span>
|
||||
<span class="caption">列表 3-6:使用 `for` 循环遍历集合中的每一个元素</span>
|
||||
|
||||
当运行这段代码,将看到与列表 3-5 一样的输出。更为重要的是,我们增强了代码安全性并消除了出现可能会导致超出数组的结尾或遍历长度不够而缺少一些元素这类 bug 机会。
|
||||
当运行这段代码,将看到与列表 3-5 一样的输出。更为重要的是,我们增强了代码安全性并消除了出现可能会导致超出数组的结尾或遍历长度不够而缺少一些元素这类 bug 的机会。
|
||||
|
||||
例如,在列表 3-5 的代码中,如果从数组 `a` 中移除一个元素但忘记更新条件为 `while index < 4`,代码将会 panic。使用`for`循环的话,就不需要惦记着在更新数组元素数量时修改其他的代码了。
|
||||
|
||||
@ -328,7 +325,7 @@ using a `for` loop</span>
|
||||
|
||||
下面是一个使用 `for` 循环来倒计时的例子,它还使用了一个我们还未讲到的方法,`rev`,用来反转 range:
|
||||
|
||||
<span class="filename">Filename: src/main.rs</span>
|
||||
<span class="filename">文件名: src/main.rs</span>
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
|
Loading…
Reference in New Issue
Block a user