Experiment Introduction - The Rust Programming Language

名词解释

Rustaceans

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

|500

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.

|475
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 the rand crate, for example, run cargo doc --open and click rand in the sidebar on the left.
注意:您不仅知道要使用哪些特征以及要从包中调用哪些方法和函数,因此每个包都有包含使用说明的文档。 Cargo 的另一个巧妙功能是运行 cargo doc --open 命令将在本地构建所有依赖项提供的文档并在浏览器中打开它。例如,如果您对 rand 包中的其他功能感兴趣,请运行 cargo doc --open 并单击左侧边栏中的 rand 。

Comparing the Guess to the Secret Number

    match guess.cmp(&secret_number) {
        Ordering::Less => println!("Too small!"),
        Ordering::Greater => println!("Too big!"),
        Ordering::Equal => println!("You win!"),
    }

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 with RUST_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.