名词解释
Rustaceans
“Rustaceans” 这个词是由 “Rust” 和 “aceans” 组合而成。“Rust” 是 Rust 编程语言的名称,而 “aceans” 部分是基于 “Rustacean” 这个词构造的。“Rustacean” 是指一种虚构的动物,一种将螃蟹和蜥蜴特征结合的生物形象,代表着 Rust 社区成员的身份和认同。
这种构词方式常见于编程社区,用来称呼特定编程语言或技术的热衷用户或从业者。类似的例子包括 JavaScript 中的 “JavaScripters”、Python 中的 “Pythonistas” 等。
总结一下,“Rustaceans” 是指 Rust 社区成员,这个词的构造方式是将 “Rust” 与 “aceans” 结合起来,以表达对 Rust 编程语言的热爱和参与。
crates
The last line,
[dependencies]
, is the start of a section for you to list any of your project’s dependencies. In Rust, packages of code are referred to as crates. We won’t need any other crates for this project, but we will in the first project in Chapter 2, so we’ll use this dependencies section then.
note= 货物
prelude
By default, Rust has a set of items defined in the standard library that it brings into the scope of every program. This set is called the prelude, and you can see everything in it in the standard library documentation.
note= 序言
1 Getting Started
1.2 Hello, World
For now, you just need to know that using a !
means that you’re calling a macro instead of a normal function and that macros don’t always follow the same rules as functions.
1.3 Hello, Cargo
- We can create a project using
cargo new
. - We can build a project using
cargo build
. - We can build and run a project in one step using
cargo run
. - We can build a project without producing a binary to check for errors using
cargo check
. - Instead of saving the result of the build in the same directory as our code, Cargo stores it in the target/debug directory.
2. Programming a Guessing Game
Storing Values with Variables
By default, Rust has a set of items defined in the standard library that it brings into the scope of every program. This set is called the prelude, and you can see everything in it in the standard library documentation.
If a type you want to use isn’t in the prelude, you have to bring that type into scope explicitly with a use
statement. Using the std::io
library provides you with a number of useful features, including the ability to accept user input.
This line creates a new variable named apples
and binds it to the value 5. In Rust, variables are immutable by default, meaning once we give the variable a value, the value won’t change. We’ll be discussing this concept in detail in the “Variables and Mutability” section in Chapter 3. To make a variable mutable, we add mut
before the variable name:
let apples = 5; // immutable
let mut bananas = 5; // mutable
Receiving User Input
io::stdin()
.read_line(&mut guess)
The &
indicates that this argument is a reference, which gives you a way to let multiple parts of your code access one piece of data without needing to copy that data into memory multiple times. References are a complex feature, and one of Rust’s major advantages is how safe and easy it is to use references. You don’t need to know a lot of those details to finish this program. For now, all you need to know is that, like variables, references are immutable by default. Hence, you need to write &mut guess
rather than &guess
to make it mutable. (Chapter 4 will explain references more thoroughly.)
Handling Potential Failure with Result
As mentioned earlier, read_line
puts whatever the user enters into the string we pass to it, but it also returns a Result
value. Result
is an enumeration, often called an enum, which is a type that can be in one of multiple possible states. We call each possible state a variant.
Result
’s variants are Ok
and Err
. The Ok
variant indicates the operation was successful, and inside Ok
is the successfully generated value. The Err
variant means the operation failed, and Err
contains information about how or why the operation failed.
Values of the Result
type, like values of any type, have methods defined on them. An instance of Result
has an expect
method that you can call. If this instance of Result
is an Err
value, expect
will cause the program to crash and display the message that you passed as an argument to expect
. If the read_line
method returns an Err
, it would likely be the result of an error coming from the underlying operating system. If this instance of Result
is an Ok
value, expect
will take the return value that Ok
is holding and return just that value to you so you can use it. In this case, that value is the number of bytes in the user’s input.
Printing Values with println!
Placeholders
The {}
set of curly brackets is a placeholder: think of {}
as little crab pincers that hold a value in place.
Using a Crate to Get More Functionality
Cargo understands Semantic Versioning (sometimes called SemVer), which is a standard for writing version numbers.
The specifier 0.8.5
is actually shorthand for ^0.8.5
, which means any version that is at least 0.8.5 but below 0.9.0.
Ensuring Reproducible Builds with the Cargo.lock File
Updating a Crate to Get a New Version
When you do want to update a crate, Cargo provides the command update
, which will ignore the Cargo.lock file and figure out all the latest versions that fit your specifications in Cargo.toml. Cargo will then write those versions to the Cargo.lock file. Otherwise, by default, Cargo will only look for versions greater than 0.8.5 and less than 0.9.0. If the rand
crate has released the two new versions 0.8.6 and 0.9.0, you would see the following if you ran cargo update
:
Generating a Random Number
First we add the line use rand::Rng;
. The Rng
trait defines methods that random number generators implement, and this trait must be in scope for us to use those methods. Chapter 10 will cover traits in detail.
As shown in the picture, If not rand::Rng
, the program will show error.
The kind of range expression we’re using here takes the form start..=end
and is inclusive on the lower and upper bounds, so we need to specify 1..=100
to request a number between 1 and 100.
note= takes the form 表现为 xx 的形式
NOTE
You won’t just know which traits to use and which methods and functions to call from a crate, so each crate has documentation with instructions for using it. Another neat feature of Cargo is that running the
cargo doc --open
command will build documentation provided by all your dependencies locally and open it in your browser. If you’re interested in other functionality in therand
crate, for example, runcargo doc --open
and clickrand
in the sidebar on the left.
注意:您不仅知道要使用哪些特征以及要从包中调用哪些方法和函数,因此每个包都有包含使用说明的文档。 Cargo 的另一个巧妙功能是运行cargo doc --open
命令将在本地构建所有依赖项提供的文档并在浏览器中打开它。例如,如果您对rand
包中的其他功能感兴趣,请运行cargo doc --open
并单击左侧边栏中的rand
。
Comparing the Guess to the Secret Number
A match
expression is made up of arms. An arm consists of a pattern to match against, and the code that should be run if the value given to match
fits that arm’s pattern.
note= arms 是分支的意思。
匹配的表达式由分支组成。一个分支由对应的模式组成, 对应的代码会执行,如果相对应的值符合分支的模式。
A few of Rust’s number types can have a value between 1 and 100: i32
, a 32-bit number; u32
, an unsigned 32-bit number; i64
, a 64-bit number; as well as others. Unless otherwise specified, Rust defaults to an i32
let guess: u32 = guess.trim().parse().expect("Please type a number!");
But wait, doesn’t the program already have a variable named guess
? It does, but helpfully Rust allows us to shadow the previous value of guess
with a new one. Shadowing lets us reuse the guess
variable name rather than forcing us to create two unique variables, such as guess_str
and guess
We’ll cover this in more detail in Chapter 3,
note= 在这个上下文中,“cover” 的意思是 “涵盖” 或 “讨论”。它表示在第三章中将详细涵盖或讨论与之前提到的主题相关的内容。因此,“We’ll cover this in more detail in Chapter 3” 可以翻译为 “我们将在第三章更详细地讨论这个” 或 “我们将在第三章更详细地涵盖这个”。具体的翻译可以根据上下文和语境进行调整。
Here, we use it to convert from a string to a number. We need to tell Rust the exact number type we want by using let guess: u32
. The colon (:
) after guess
tells Rust we’ll annotate the variable’s type. Rust has a few built-in number types; the u32
seen here is an unsigned, 32-bit integer. It’s a good default choice for a small positive number. You’ll learn about other number types in Chapter 3.
note= 尝试输入错误的值,展示出来的值为
thread ‘main’ panicked at src/main.rs:25:10:
Please type a number!: ParseIntError { kind: InvalidDigit }
stack backtrace:
0: rust_begin_unwind
at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/std/src/panicking.rs:597:5
1: core::panicking::panic_fmt
at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/core/src/panicking.rs:72:14
2: core::result::unwrap_failed
at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/core/src/result.rs:1652:5
3: core::result::Result<T,E>::expect
at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/core/src/result.rs:1034:23
4: guessing_game::main
at ./src/main.rs:23:22
5: core::ops::function::FnOnce::call_once
at /rustc/79e9716c980570bfd1f666e3b16ac583f0168962/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run withRUST_BACKTRACE=full
for a verbose backtrace.
// --snip--
io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
println!("You guessed: {guess}");
// --snip--
The underscore, _
, is a catchall value; in this example, we’re saying we want to match all Err
values, no matter what information they have inside them.