check to ch03-02

pull/268/head
KaiserY 6 years ago
parent dcf04d8ffa
commit 0f9f9d5554

@ -1,14 +1,14 @@
## Hello, Cargo!
> [ch01-03-hello-cargo.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch01-03-hello-cargo.md)
> [ch01-03-hello-cargo.md](https://github.com/rust-lang/book/blob/master/src/ch01-03-hello-cargo.md)
> <br>
> commit 7480e811ab5ad8d53a5b854d9b0c7a5a4f58499f
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
Cargo 是 Rust 的构建系统和包管理器。大多数 Rustacean 们使用 Cargo 来管理他们的 Rust 项目,因为它可以为你处理很多任务,比如构建代码、下载依赖库并编译这些库。(我们把代码所需要的库叫做 **依赖***dependencies*))。
最简单的 Rust 程序,比如我们刚刚编写的,没有任何依赖。所以如果使用 Cargo 来构建 Hello, world! 项目,将只会用到 Cargo 的构建代码那部分功能。随着编写的 Rust 程序更加复杂,你会添加依赖,如果你一开始就使用 Cargo 的话,添加依赖将会变得简单许多。
最简单的 Rust 程序,比如我们刚刚编写的,没有任何依赖。所以如果使用 Cargo 来构建 Hello, world! 项目,将只会用到 Cargo 的构建代码那部分功能。如果编写更为复杂的 Rust 程序,你会添加依赖,这样如果你一开始就使用 Cargo 的话,添加依赖将会变得简单许多。
由于绝大多数 Rust 项目使用 Cargo本书接下来的部分假设你也使用 Cargo。如果使用 “安装” 章节介绍的官方安装包的话,则自带了 Cargo。如果通过其他方式安装的话可以在终端输入如下命令检查是否安装了 Cargo
由于绝大多数 Rust 项目使用 Cargo本书接下来的部分假设你也使用 Cargo。如果使用 “安装” 部分介绍的官方安装包的话,则自带了 Cargo。如果通过其他方式安装的话可以在终端输入如下命令检查是否安装了 Cargo
```text
$ cargo --version
@ -21,17 +21,17 @@ $ cargo --version
我们使用 Cargo 创建一个新项目,然后看看与上面的 Hello, world! 项目有什么不同。回到 *projects* 目录(或者你存放代码的目录)。接着,可在任何操作系统下运行以下命令:
```text
$ cargo new hello_cargo --bin
$ cargo new hello_cargo
$ cd hello_cargo
```
第一行命令新建了名为 *hello_cargo*二进制可执行程序。为 `cargo new` 传入 `--bin` 参数会生成一个可执行程序(通常就叫做 **二进制文件***binary*),而不是一个库。项目被命名为 `hello_cargo`,同时 Cargo 在一个同名目录中创建项目文件。
第一行命令新建了名为 *hello_cargo*目录。我们将项目命名为 *hello_cargo*,同时 Cargo 在一个同名目录中创建项目文件。
进入 *hello_cargo* 目录并列出文件。将会看到 Cargo 生成了两个文件和一个目录:一个 *Cargo.toml* 文件,一个 *src* 目录,以及位于 *src* 目录中 *main.rs* 文件。它也在 *hello_cargo* 目录初始化了一个 git 仓库,以及一个 *.gitignore* 文件。
> 注意Git 是一个常用的版本控制系统version control system VCS。可以通过 `--vcs` 参数使 `cargo new` 切换到其它版本控制系统VCS或者不使用 VCS。运行 `cargo new --help` 参看可用的选项。
请选用文本编辑器打开 *Cargo.toml* 文件。它应该看起来如示例 1-2 所示:
自行选用文本编辑器打开 *Cargo.toml* 文件。它应该看起来如示例 1-2 所示:
<span class="filename">文件名: Cargo.toml</span>
@ -40,6 +40,7 @@ $ cd hello_cargo
name = "hello_cargo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
[dependencies]
```
@ -52,9 +53,9 @@ authors = ["Your Name <you@example.com>"]
第一行,`[package]`是一个片段section标题表明下面的语句用来配置一个包。随着我们在这个文件增加更多的信息还将增加其他片段section
接下来的行设置了 Cargo 编译程序所需的配置项目的名称、版本和作者。Cargo 从环境中获取你的名字和 email 信息,所以如果这些信息不正确,请修改并保存此文件。
接下来的行设置了 Cargo 编译程序所需的配置项目的名称、版本和作者。Cargo 从环境中获取你的名字和 email 信息,所以如果这些信息不正确,请修改并保存此文件。附录 E 会介绍 `edition` 的值。
最后一行,`[dependencies]`,是罗列项目依赖的片段。在 Rust 中,代码包被称为 *crates*。这个项目并不需要其他的 crate不过在第二章的第一个项目会用到依赖那时会用得上这个片段。
最后一行,`[dependencies]`,是罗列项目依赖的片段的开始。在 Rust 中,代码包被称为 *crates*。这个项目并不需要其他的 crate不过在第二章的第一个项目会用到依赖那时会用得上这个片段。
现在打开 *src/main.rs* 看看:
@ -85,7 +86,7 @@ $ cargo build
这个命令会创建一个可执行文件 *target/debug/hello_cargo* (在 Windows 上是 *target\debug\hello_cargo.exe*),而不是放在目前目录下。可以通过这个命令运行可执行文件:
```text
$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
$ ./target/debug/hello_cargo # 或者在 Windows 下为 .\target\debug\hello_cargo.exe
Hello, world!
```
@ -109,15 +110,16 @@ $ cargo run
Running `target/debug/hello_cargo`
Hello, world!
```
Cargo 还提供了一个叫 `cargo check` 的命令。该命令快速检查代码确保其可以编译,但并不产生可执行文件:
```text
$ cargo check
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
```
为什么你会不需要可执行文件呢?通常 `cargo check` 要比 `cargo build` 快得多,因为它省略了生成可执行文件的步骤。如果编写代码时持续的进行检查,`cargo check` 会加速开发!为此很多 Rustaceans 编写代码时定期运行 `cargo check` 确保它们可以编译。当准备好使用可执行文件时才运行 `cargo build`
为什么你会不需要可执行文件呢?通常 `cargo check` 要比 `cargo build` 快得多,因为它省略了生成可执行文件的步骤。如果你在编写代码时持续的进行检查,`cargo check` 会加速开发!为此很多 Rustaceans 编写代码时定期运行 `cargo check` 确保它们可以编译。当准备好使用可执行文件时才运行 `cargo build`
我们回顾下已学习的 Cargo 内容:
@ -125,7 +127,7 @@ $ cargo check
* 可以使用 `cargo run` 一步构建并运行项目。
* 有别于将构建结果放在与源码相同的目录Cargo 会将其放到 *target/debug* 目录。
使用 Cargo 的一个额外的优点是,不管你使用什么操作系统,其命令都是一样的。所以从此以后本书将不再为 Linux 和 macOS 以及 Windows 提供相应的命令。
使用 Cargo 的一个额外的优点是,不管你使用什么操作系统,其命令都是一样的。所以从现在开始本书将不再为 Linux 和 macOS 以及 Windows 提供相应的命令。
### 发布release构建
@ -149,7 +151,7 @@ $ cargo build
## 总结
你已经踏上了 Rust 之旅!在本章中,你学习了如何:
你已经准备好开启 Rust 之旅了!在本章中,你学习了如何:
* 使用 `rustup` 安装最新稳定版的 Rust
* 更新到新版的 Rust
@ -157,4 +159,4 @@ $ cargo build
* 直接通过 `rustc` 编写并运行 Hello, world! 程序
* 使用 Cargo 创建并运行新项目
是时候通过构建更实的程序来熟悉读写 Rust 代码了。所以在下一章,我们会构建一个猜猜看游戏程序。如果你更愿意从学习 Rust 常用的编程概念开始,请阅读第三章,接着再回到第二章。
是时候通过构建更实质性的程序来熟悉读写 Rust 代码了。所以在第二章我们会构建一个猜猜看游戏程序。如果你更愿意从学习 Rust 常用的编程概念开始,请阅读第三章,接着再回到第二章。

@ -1,8 +1,8 @@
# 编写 猜猜看 游戏
> [ch02-00-guessing-game-tutorial.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch02-00-guessing-game-tutorial.md)
> [ch02-00-guessing-game-tutorial.md](https://github.com/rust-lang/book/blob/master/src/ch02-00-guessing-game-tutorial.md)
> <br>
> commit 7480e811ab5ad8d53a5b854d9b0c7a5a4f58499f
> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37
让我们一起动手完成一个项目,来快速上手 Rust本章将介绍 Rust 中一些常用概念,并通过真实的程序来展示如何运用它们。你将会学到 `let`、`match`、方法、关联函数、外部 crate 等知识!后续章节会深入探讨这些概念的细节。在这一章,我们将做基础练习。
@ -13,11 +13,11 @@
要创建一个新项目,进入第一章中创建的 *projects* 目录,使用 Cargo 新建一个项目,如下:
```text
$ cargo new guessing_game --bin
$ cargo new guessing_game
$ cd guessing_game
```
第一个命令,`cargo new`,它获取项目的名称(`guessing_game`)作为第一个参数。`--bin` 参数告诉 Cargo 创建一个二进制项目,与第一章类似。第二个命令进入到新创建的项目目录。
第一个命令,`cargo new`,它获取项目的名称(`guessing_game`)作为第一个参数。第二个命令进入到新创建的项目目录。
看看生成的 *Cargo.toml* 文件:
@ -119,7 +119,7 @@ println!("Please input your guess.");
let mut guess = String::new();
```
现在程序开始变得有意思了!这一小行代码发生了很多事。注意这是一个 `let` 语句,用来创建 **变量**。这里是另外一个例子:
现在程序开始变得有意思了!这一小行代码发生了很多事。注意这是一个 `let` 语句,用来创建 **变量***variable*。这里是另外一个例子:
```rust,ignore
let foo = bar;
@ -128,11 +128,11 @@ let foo = bar;
这行代码新建了一个叫做 `foo` 的变量并把它绑定到值 `bar` 上。在 Rust 中,变量默认是不可变的。我们将会在第三章的 “变量与可变性” 部分详细讨论这个概念。下面的例子展示了如何在变量名前使用 `mut` 来使一个变量可变:
```rust,ignore
let foo = 5; // immutable
let mut bar = 5; // mutable
let foo = 5; // 不可变
let mut bar = 5; // 可变
```
> 注意:`//` 语法开始一个注释持续到行尾。Rust 忽略注释中的所有内容,将在第三章中详细介绍注释。
> 注意:`//` 语法开始一个注释持续到行尾。Rust 忽略注释中的所有内容,第三章将会详细介绍注释。
让我们回到猜猜看程序中。现在我们知道了 `let mut guess` 会引入一个叫做 `guess` 的可变变量。等号(`=`)的右边是 `guess` 所绑定的值,它是 `String::new` 的结果,这个函数会返回一个 `String` 的新实例。[`String`][string]<!-- ignore --> 是一个标准库提供的字符串类型,它是 UTF-8 编码的可增长文本块。
@ -214,7 +214,7 @@ Rust 警告我们没有使用 `read_line` 的返回值 `Result`,说明有一
### 使用 `println!` 占位符打印值
除了位于结尾的大括号,目前为止就只有一行代码值得讨论一下了,就是这一行:
除了位于结尾的大括号,目前为止就只有一行代码值得讨论一下了,就是这一行:
```rust,ignore
println!("You guessed: {}", guess);
@ -295,9 +295,9 @@ $ cargo build
在更新完 registry 后Cargo 检查 `[dependencies]` 片段并下载缺失的 crate 。本例中,虽然只声明了 `rand` 一个依赖,然而 Cargo 还是额外获取了 `libc` 的拷贝,因为 `rand` 依赖 `libc` 来正常工作。下载完成后Rust 编译依赖,然后使用这些依赖编译项目。
如果不做任何修改,立刻再次运行 `cargo build`,则不会看到任何除了 `Finished` 完成提示之外的输出。Cargo 知道它已经下载并编译了依赖,同时 *Cargo.toml* 文件也没有变动。Cargo 还知道代码也没有任何修改,所以它不会重新编译代码。因为无事可做,它简单的退出了。
如果不做任何修改,立刻再次运行 `cargo build`,则不会看到任何除了 `Finished` 之外的输出。Cargo 知道它已经下载并编译了依赖,同时 *Cargo.toml* 文件也没有变动。Cargo 还知道代码也没有任何修改,所以它不会重新编译代码。因为无事可做,它简单的退出了。
如果打开 *src/main.rs* 文件,做一些无关紧要的修改,保存并再次构建,会出现两行输出:
如果打开 *src/main.rs* 文件,做一些无关紧要的修改,保存并再次构建,会出现两行输出:
```text
$ cargo build
@ -311,7 +311,7 @@ $ cargo build
Cargo 有一个机制来确保任何人在任何时候重新构建代码都会产生相同的结果Cargo 只会使用你指定的依赖版本,除非你又手动指定了别的。例如,如果下周 `rand` crate 的 `0.3.15` 版本出来了,它修复了一个重要的 bug同时也含有一个会破坏代码运行的缺陷这时会发生什么呢
这个问题的答案是 *Cargo.lock* 文件。它在第一次运行 `cargo build` 时创建,并放在 *guessing_game* 目录。当第一次构建项目时Cargo 计算出所有符合要求的依赖版本并写入 *Cargo.lock* 文件。当将来构建项目时Cargo 会发现 *Cargo.lock* 已存在并使用其中指定的版本,而不是再次计算所有的版本。这使得你拥有了一个自动化的可重现的构建。换句话说,项目会持续使用 `0.3.14` 直到你显式升级,感谢 *Cargo.lock* 文件。
这个问题的答案是 *Cargo.lock* 文件。它在第一次运行 `cargo build` 时创建,并放在 *guessing_game* 目录。当第一次构建项目时Cargo 计算出所有符合要求的依赖版本并写入 *Cargo.lock* 文件。当将来构建项目时Cargo 会发现 *Cargo.lock* 已存在并使用其中指定的版本,而不是再次计算所有的版本。这使得你拥有了一个自动化的可重现的构建。换句话说,项目会持续使用 `0.3.14` 直到你显式升级,多亏有了 *Cargo.lock* 文件。
#### 更新 crate 到一个新版本
@ -337,20 +337,18 @@ rand = "0.4.0"
下一次运行 `cargo build`Cargo 会从 registry 更新可用的 crate并根据你指定的新版本重新计算。
第十四章会讲到 [Cargo][doccargo]<!-- ignore --> 及其[生态系统][doccratesio]<!-- ignore -->的更多内容,不过目前你只需要了解这么多。通过 Cargo 复用库文件非常容易,因此 Rustacean 能够编写出由很多包组装而成的更轻巧的项目。
第十四章会讲到 [Cargo][doccargo]<!-- ignore --> 及其[生态系统][doccratesio]<!-- ignore --> 的更多内容,不过目前你只需要了解这么多。通过 Cargo 复用库文件非常容易,因此 Rustacean 能够编写出由很多包组装而成的更轻巧的项目。
[doccargo]: http://doc.crates.io
[doccratesio]: http://doc.crates.io/crates-io.html
### 生成一个随机数
你已经把 `rand` crate 添加到 *Cargo.toml* 了,让我们开始 **使用** `rand` 吧。下一步是更新 *src/main.rs*,如示例 2-3 所示
你已经把 `rand` crate 添加到 *Cargo.toml* 了,让我们开始 **使用** `rand` 吧。下一步是更新 *src/main.rs*,如示例 2-3 所示
<span class="filename">文件名: src/main.rs</span>
```rust,ignore
extern crate rand;
use std::io;
use rand::Rng;
@ -378,11 +376,11 @@ fn main() {
接下来增加了另一行 `use``use rand::Rng`。`Rng` 是一个 trait它定义了随机数生成器应实现的方法想使用这些方法的话此 trait 必须在作用域中。第十章会详细介绍 trait。
另外,中间还新增加了两行。`rand::thread_rng` 函数提供实际使用的随机数生成器:它位于当前执行线程本地,并从操作系统获取 seed。接下来调用随机数生成器的 `gen_range` 方法。这个方法由刚才引入到作用域的 `Rng` trait 定义。`gen_range` 方法获取两个数字作为参数,并生成一个范围在两者之间的随机数。它包含下限但不包含上限,所以需要指定 `1``101` 来请求一个 1 和 100 之间的数。
另外,中间还新增加了两行。`rand::thread_rng` 函数提供实际使用的随机数生成器:它位于当前执行线程本地环境中,并从操作系统获取 seed。接下来调用随机数生成器的 `gen_range` 方法。这个方法由刚才引入到作用域的 `Rng` trait 定义。`gen_range` 方法获取两个数字作为参数,并生成一个范围在两者之间的随机数。它包含下限但不包含上限,所以需要指定 `1``101` 来请求一个 1 和 100 之间的数。
> 注意:你不可能凭空就知道应该 use 哪个 trait 以及该从 crate 中调用哪个方法。crate 的使用说明位于其文档中。Cargo 有一个很棒的功能是:运行 `cargo doc --open` 命令来构建所有本地依赖提供的文档,并在浏览器中打开。例如,假设你对 `rand` crate 中的其他功能感兴趣,你可以运行 `cargo doc --open` 并点击左侧导航栏中的 `rand`
新增加的第二行代码打印出了秘密数字。这在开发程序时很有用,因为可以测试它,不过在最终版本中会删掉它。游戏一开始就打印出结果就没什么可玩的了!
新增加的第二行代码打印出了秘密数字。这在开发程序时很有用,因为可以测试它,不过在最终版本中会删掉它。如果游戏一开始就打印出结果就没什么可玩的了!
尝试运行程序几次:
@ -500,13 +498,13 @@ let guess: u32 = guess.trim().parse()
这里创建了一个叫做 `guess` 的变量。不过等等,不是已经有了一个叫做 `guess` 的变量了吗?确实如此,不过 Rust 允许用一个新值来 **隐藏** *shadow* `guess` 之前的值。这个功能常用在需要转换值类型之类的场景。它允许我们复用 `guess` 变量的名字,而不是被迫创建两个不同变量,诸如 `guess_str``guess` 之类。(第三章会介绍 shadowing 的更多细节。)
我们将 `guess` 绑定到 `guess.trim().parse()` 表达式上。表达式中的 `guess` 是包含输入的原始 `String` 类型。`String` 实例的 `trim` 方法会去除字符串开头和结尾的空白字符。`u32` 只能由数字字符转换,不过用户必须输入 <span class="keystroke">return</span> 键才能让 `read_line` 返回,然而用户按下 <span class="keystroke">return</span> 键时会在字符串中增加一个换行newline符。例如用户输入 <span class="keystroke">5</span> 并按下 <span class="keystroke">return</span>`guess` 看起来像这样:`5\n`。`\n` 代表 “换行”,回车键。`trim` 方法消除 `\n`,只留下`5`。
我们将 `guess` 绑定到 `guess.trim().parse()` 表达式上。表达式中的 `guess` 是包含输入的原始 `String` 类型。`String` 实例的 `trim` 方法会去除字符串开头和结尾的空白字符。`u32` 只能由数字字符转换,不过用户必须输入 <span class="keystroke">enter</span> 键才能让 `read_line` 返回,然而用户按下 <span class="keystroke">enter</span> 键时会在字符串中增加一个换行newline符。例如用户输入 <span class="keystroke">5</span> 并按下 <span class="keystroke">enter</span>`guess` 看起来像这样:`5\n`。`\n` 代表 “换行”,回车键。`trim` 方法消除 `\n`,只留下 `5`
[字符串的 `parse` 方法][parse]<!-- ignore --> 将字符串解析成数字。因为这个方法可以解析多种数字类型,因此需要告诉 Rust 具体的数字类型,这里通过 `let guess: u32` 指定。`guess` 后面的冒号(`:`)告诉 Rust 我们指定了变量的类型。Rust 有一些内建的数字类型;`u32` 是一个无符号的 32 位整型。对于不大的正整数来说,它是不错的类型,第三章还会讲到其他数字类型。另外,程序中的 `u32` 注解以及与 `secret_number` 的比较,意味着 Rust 会推断出 `secret_number` 也是 `u32` 类型。现在可以使用相同类型比较两个值了!
[parse]: https://doc.rust-lang.org/std/primitive.str.html#method.parse
`parse` 调用很容易产生错误。例如,字符串中包含 `A👍%`,就无法将其转换为一个数字。因此,`parse` 方法返回一个 `Result` 类型。像之前 “使用 `Result` 类型来处理潜在的错误” 讨论的 `read_line` 方法那样,再次按部就班的用 `expect` 方法处理即可。如果 `parse` 不能从字符串生成一个数字,返回一个 `Result::Err` 时,`expect` 会使游戏崩溃并打印附带的信息。如果 `parse` 成功地将字符串转换为一个数字,它会返回 `Result::Ok`,然后 `expect` 会返回 `Ok` 中的数字。
`parse` 调用很容易产生错误。例如,字符串中包含 `A👍%`,就无法将其转换为一个数字。因此,`parse` 方法返回一个 `Result` 类型。像之前 “使用 `Result` 类型来处理潜在的错误” 讨论的 `read_line` 方法那样,再次按部就班的用 `expect` 方法处理即可。如果 `parse` 不能从字符串生成一个数字,返回一个 `Result` 的 `Err` 成员时,`expect` 会使游戏崩溃并打印附带的信息。如果 `parse` 成功地将字符串转换为一个数字,它会返回 `Result` 的 `Ok` 成员,然后 `expect` 会返回 `Ok` 中的数字。
现在让我们运行程序!
@ -552,7 +550,7 @@ Too big!
}
```
如上所示,我们将提示用户猜测之后的所有内容放入了循环。确保 loop 循环中的代码多缩进四个空格,再次运行程序。注意这里有一个新问题,因为程序忠实地执行了我们的要求:永远地请求另一个猜测,用户好像法退出啊!
如上所示,我们将提示用户猜测之后的所有内容放入了循环。确保 loop 循环中的代码多缩进四个空格,再次运行程序。注意这里有一个新问题,因为程序忠实地执行了我们的要求:永远地请求另一个猜测,用户好像法退出啊!
用户总能使用 <span class="keystroke">ctrl-c</span> 终止程序。不过还有另一个方法跳出无限循环,就是 “比较猜测与秘密数字” 部分提到的 `parse`:如果用户输入的答案不是一个数字,程序会崩溃。用户可以利用这一点来退出,如下所示:
@ -666,8 +664,6 @@ You win!
<span class="filename">文件名: src/main.rs</span>
```rust,ignore
extern crate rand;
use std::io;
use std::cmp::Ordering;
use rand::Rng;

@ -1,13 +1,41 @@
# 通用编程概念
> [ch03-00-common-programming-concepts.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch03-00-common-programming-concepts.md)
> [ch03-00-common-programming-concepts.md](https://github.com/rust-lang/book/blob/master/src/ch03-00-common-programming-concepts.md)
> <br>
> commit b64de01431cdf1020ad3358d2f83e46af68a39ed
> commit 1fedfc4b96c2017f64ecfcf41a0a07e2e815f24f
本章介绍一些几乎所有编程语言都有的概念,以及它们在 Rust 中是如何工作的。很多编程语言的核心概念都是共通的,本章中展示的概念都不是 Rust 所特有的,不过我们会在 Rust 上下文中讨论它们,并解释使用这些概念的惯例。
具体来说,我们将会学习变量、基本类型、函数、注释和控制流。每一个 Rust 程序中都会用到这些基础知识,提早学习这些概念会让你在起步时就打下坚实的基础。
> ### 关键字
>
> Rust 语言有一组保留的 **关键字***keywords*),就像大部分语言一样,它们只能由语言本身使用。记住,你不能使用这些关键字作为变量或函数的名称。大部分关键字有特殊的意义,你将在你的 Rust 程序中使用它们完成各种任务;一些关键字目前没有相应的功能,是为将来可能添加的功能保留的。可以在附录 A 中找到关键字的列表。
## 关键字
Rust 语言有一组保留的 **关键字***keywords*),就像大部分语言一样,它们只能由语言本身使用。记住,你不能使用这些关键字作为变量或函数的名称。大部分关键字有特殊的意义,你将在 Rust 程序中使用它们完成各种任务;一些关键字目前没有相应的功能,是为将来可能添加的功能保留的。可以在附录 A 中找到关键字的列表。
## 标识符
这里我们将对本书中的一些概念做一些解释变量、函数、结构体等等。所有这些都需要名称。Rust 中的名称被称为 “标识符”“identifier”它们可以是任意非空的 ASCII 字符串,不过有如下限制:
要么是:
* 第一个字符是字母。
* 其它字符是字母数字或者 _。
或者是:
* 第一个字符是 _。
* 标识符需多于一个字符。单独的 _ 不是标识符。
* 其它字符是字母数字或者 _。
### 原始标识符
有时出于某种原因你可能需要将关键字作为名称。比如你需要调用 C 语言库中名为 *match* 的函数,在 C 语言中 *match* 不是关键字。为此你可以使用 “原始标识符”“raw identifier”。原始标识符以 `r#` 开头:
```rust,ignore
let r#fn = "this variable is named 'fn' even though that's a keyword";
// 调用名为 'match' 的函数
r#match();
```
你无需经常用到原始标识符,但是当你 **真正** 需要它们时可以这么做。

@ -1,18 +1,18 @@
## 变量和可变性
> [ch03-01-variables-and-mutability.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch03-01-variables-and-mutability.md)
> [ch03-01-variables-and-mutability.md](https://github.com/rust-lang/book/blob/master/src/ch03-01-variables-and-mutability.md)
> <br>
> commit f949ff883628db8ed2f2f5f19e146ebf19ed6a6f
> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37
第二章中提到过变量默认是不可改变的immutable。这是推动你以充分利用 Rust 提供的安全性和简单并发性编写代码的众多方式之一。不过,你仍然可以使用可变变量。让我们探讨一下 Rust 拥抱不可变性的原因及方法,以及何时你不想使用不可变性。
第二章中提到过变量默认是不可改变的immutable。这是推动你以充分利用 Rust 提供的安全性和简单并发性编写代码的众多方式之一。不过,你仍然可以使用可变变量。让我们探讨一下 Rust 拥抱不可变性的原因及方法,以及何时你不想使用不可变性。
当变量不可变时,一旦值被绑定一个名称上,你就不能改变这个值。为了对此进行说明,使用 `cargo new --bin variables` 命令在 *projects* 目录生成一个叫做 *variables* 的新项目。
当变量不可变时,一旦值被绑定一个名称上,你就不能改变这个值。为了对此进行说明,使用 `cargo new variables` 命令在 *projects* 目录生成一个叫做 *variables* 的新项目。
接着,在新建的 *variables* 目录,打开 *src/main.rs* 并将代码替换为如下代码,这些代码还不能编译:
<span class="filename">文件名: src/main.rs</span>
```rust,ignore
```rust,ignore,does_not_compile
fn main() {
let x = 5;
println!("The value of x is: {}", x);
@ -40,7 +40,7 @@ error[E0384]: cannot assign twice to immutable variable `x`
在尝试改变预设为不可变的值时,产生编译时错误是很重要的,因为这种情况可能导致 bug。如果一部分代码假设一个值永远也不会改变而另一部分代码改变了这个值第一部分代码就有可能以不可预料的方式运行。不得不承认这种 bug 的起因难以跟踪,尤其是第二部分代码只是 **有时** 会改变值。
Rust 编译器保证,如果声明一个值不会变,它就真的不会变。这意味着当阅读和编写代码时,不需要追踪一个值如何以及哪里可能会被改变,从而使得代码易于推导。
Rust 编译器保证,如果声明一个值不会变,它就真的不会变。这意味着当阅读和编写代码时,不需要追踪一个值如何和在哪可能会被改变,从而使得代码易于推导。
不过可变性也是非常有用的。变量只是默认不可变;正如在第二章所做的那样,你可以在变量名之前加 `mut` 来使其可变。除了允许改变值之外,`mut` 向读者表明了其他代码将会改变这个变量值的意图。
@ -84,7 +84,7 @@ The value of x is: 6
最后一个区别是,常量只能被设置为常量表达式,而不能是函数调用的结果,或任何其他只能在运行时计算出的值。
这是一个声明常量的例子,它的名称是 `MAX_POINTS`,值是 100,000。Rust 常量的命名规范是使用下划线分隔的大写字母):
这是一个声明常量的例子,它的名称是 `MAX_POINTS`,值是 100,000。Rust 常量的命名规范是使用下划线分隔的大写字母单词,并且可以在数字字面值中插入下划线来提升可读性
```rust
const MAX_POINTS: u32 = 100_000;
@ -133,7 +133,7 @@ let spaces = spaces.len();
这里允许第一个 `spaces` 变量是字符串类型,而第二个 `spaces` 变量,它是一个恰巧与第一个变量同名的崭新变量,是数字类型。隐藏使我们不必使用不同的名字,如 `spaces_str``spaces_num`;相反,我们可以复用 `spaces` 这个更简单的名字。然而,如果尝试使用 `mut`,将会得到一个编译时错误,如下所示:
```rust,ignore
```rust,ignore,does_not_compile
let mut spaces = " ";
spaces = spaces.len();
```

@ -1,10 +1,10 @@
## 数据类型
> [ch03-02-data-types.md](https://github.com/rust-lang/book/blob/master/second-edition/src/ch03-02-data-types.md)
> [ch03-02-data-types.md](https://github.com/rust-lang/book/blob/master/src/ch03-02-data-types.md)
> <br>
> commit f949ff883628db8ed2f2f5f19e146ebf19ed6a6f
> commit a86c1d315789b3ca13b20d50ad5005c62bdd9e37
在 Rust 中,每一个值都属于某一个 **数据类型***data type*),这告诉 Rust 它被指定为何种数据以便明确数据处理方式。我们将看到两类数据类型标量scalar和复合compound
在 Rust 中,每一个值都属于某一个 **数据类型***data type*),这告诉 Rust 它被指定为何种数据,以便明确数据处理方式。我们将看到两类数据类型子集标量scalar和复合compound
记住Rust 是 **静态类型***statically typed*)语言,也就是说在编译时就必须知道所有变量的类型。根据值及其使用方式,编译器通常可以推断出我们想要用的类型。当多种类型均有可能时,比如第二章的 “比较猜测的数字和秘密数字” 使用 `parse``String` 转换为数字时,必须增加类型注解,像这样:
@ -65,6 +65,12 @@ error[E0282]: type annotations needed
那么该使用哪种类型的数字呢如果拿不定主意Rust 的默认类型通常就很好,数字类型默认是 `i32`:它通常是最快的,甚至在 64 位系统上也是。`isize` 或 `usize` 主要作为某些集合的索引。
##### 整型溢出
比方说有一个 `u8` ,它可以存放从零到 `255` 的值。那么当你将其修改为 `256` 时会发生什么呢?这被称为 “整型溢出”“integer overflow” ),关于这一行为 Rust 有一些有趣的规则。当在 debug 模式编译时Rust 检查这类问题并使程序 *panic*,这个术语被 Rust 用来表明程序因错误而退出。第九章会详细介绍 panic。
在 release 构建中Rust 不检测溢出,相反会进行一种被称为 “twos complement wrapping” 的操作。简而言之,`256` 变成 `0``257` 变成 `1`,依此类推。依赖溢出被认为是一种错误,即便可能出现这种行为。如果你确实需要这种行为,标准库中有一个类型显式提供此功能,`Wrapping`。
#### 浮点型
Rust 也有两个原生的 **浮点数***floating-point numbers*类型它们是带小数点的数字。Rust 的浮点数类型是 `f32``f64`,分别占 32 位和 64 位。默认类型是 `f64`,因为在现代 CPU 中,它与 `f32` 速度几乎一样,不过精度更高。
@ -217,6 +223,14 @@ let months = ["January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December"];
```
数组的类型比较有趣;它看起来像 `[type; number]`。例如:
```rust
let a: [i32; 5] = [1, 2, 3, 4, 5];
```
首先是方括号;这看起来像创建数组的语法。其中有两部分由分号分割的信息。第一部分是数组中每个元素的类型。因为所有元素都是相同类型的,所以只需列出一次。分号之后,是一个表示数组长度的数字。因为数组是固定长度的,该数字也一直保持不变,即便数组的元素被修改,它也不会增长火缩小。
##### 访问数组元素
数组是一整块分配在栈上的内存。可以使用索引来访问数组的元素,像这样:

Loading…
Cancel
Save