Rust programming 3


基础永远值得花费90%的精力去学习加强。认识实践的重要性。

Ax Rust Game

让我们一起完成一个动手项目,进入 Rust!实践出真知。您将了解let, match, 方法、相关函数、使用外部 crate 等等!

我们将实现一个经典的初学者编程问题:猜谜游戏。它是这样工作的:程序将生成一个介于 1 和 100 之间的随机整数。然后它会提示玩家输入猜测。输入猜测值后,程序将指示猜测值是过低还是过高。如果猜对了,游戏将打印祝贺信息并退出。

Bx Create Project

要建立一个新项目

$ cargo new guessing_game
$ cd guessing_game

测试一下输出默认的hello world

$ cargo run

Cx Programming

猜测处理机制

直接在默认生成的这个文件中编写

use std::io;

fn main() {
    println!("Guess the number!");

    println!("Please input your guess.");

    let mut guess = String::new();

    io::stdin()
        .read_line(&mut guess)
        .expect("Failed to read line");

    println!("You guessed: {guess}");
}

解析:

io库来自标准库,称为std,所以需要引入。

fn声明一个函数体,main函数是程序的入口。

println!是一个将字符串打印到屏幕的宏。

赋值到变量

我们将创建一个变量来存储用户输入

let mut guess = String::new();

使用let语句来创建变量

let apples = 5;

这一行创建了一个名为 5 的新变量apples并将其绑定到值 5。在 Rust 中,变量默认是不可变的,添加mut使其可变。

let apples = 5; // immutable
let mut bananas = 5; // mutable

接收用户输入

use std::io;,现在我们将从模块中调用该stdin函数io,这将允许我们处理用户输入。

    io::stdin()
        .read_line(&mut guess)

该行.read_line(&mut guess)调用read_line标准输入句柄上的方法来获取用户的输入。用户输入的任何内容放入标准输入并将其附加到字符串中(不覆盖其内容),所以我们因此将该字符串作为参数传递。字符串参数需要是可变的,以便该方法可以更改字符串的内容。

&表示此参数是一个引用它为您提供了一种方法,让您的代码的多个部分访问一个数据,而无需多次将该数据复制到内存中。引用是一个复杂的特性,Rust 的主要优势之一是使用引用是多么安全和容易。你不需要知道很多细节来完成这个程序。现在,您需要知道的是,与变量一样,引用在默认情况下是不可变的。因此,您需要编写&mut guess而不是 &guess使其可变。

Result的潜在故障

者是result的一个处理错误的机制。不要的话会报错(编译的时候,不影响运行)。

        .expect("Failed to read line");

可以写成一行

io::stdin().read_line(&mut guess).expect("Failed to read line");

具体就不说了。

Println!使用占位符打印内容

    println!("You guessed: {guess}");

您可以使用花括号打印多个值,第一组花括号保存格式字符串后列出的第一个值,第二组保存第二个值,依此类推

let x = 5;
let y = 10;

println!("x = {} and y = {}", x, y);

此代码将打印x = 5 and y = 10.

测试处理机制

使用cargo run

$ cargo run       
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running `target/debug/guessing_game`
Guess the number!
Please input your guess.
1
You guessed: 1

至此,游戏的第一部分就完成了:我们从键盘获取输入,然后打印出来。

生成密码

接下来,我们需要生成一个用户将尝试猜测的秘密数字。密码每次都应该不同,这样游戏就可以玩不止一次。我们将使用 1 到 100 之间的随机数,这样游戏不会太难。Rust 的标准库中还没有包含随机数功能。然而,Rust 团队确实提供具有上述功能的rand板条箱(crate)。

使用板条箱获得更多功能

请记住,一个 crate 是 Rust 源代码文件的集合。我们一直在构建的项目是一个二进制 crate,它是一个可执行文件。rand crate 是一个库 crate,其中包含旨在用于其他程序且不能单独执行的代码。

Cargo 对外部 crate 的协调是 Cargo 真正发光的地方!

引入:我们需要修改Cargo.toml文件以包含randcrate 作为依赖项。请务必rand完全按照我们在此处指定的版本号使用此版本号,否则本教程中的代码示例可能无法正常工作。

现在打开该文件并将以下行添加到[dependencies]Cargo 为您创建的部分标题下方的底部

文件名:Cargo.toml

rand = "0.8.3"

不改动,则不会更新版本。

使用Cargo.lock文件确保可重现的构建

cargo只会用你指定的版本,这个文件就是为了确保它。

更新板条箱

如果你想更新,可以使用下面的命令,它忽略lock文件并写入lock。

$ cargo update
    Updating crates.io index
    Updating rand v0.8.3 -> v0.8.4

如果有两个新版本,它不会更新到最新的,而是最近的一次更新,如需更新需要自己更改Cargo.toml。

生成随机数

让我们开始使用rand来生成一个数字来猜测

use rand::Rng;
    let secret_number = rand::thread_rng().gen_range(1..=100);

不知道怎么用?Cargo 的另一个巧妙功能是运行该cargo doc --open命令将在本地构建所有依赖项提供的文档并在浏览器中打开它。

比较

现在我们有了用户输入和一个随机数,我们可以比较它们。

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    // --snip--

    println!("You guessed: {guess}");

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

报错了,为什么?以为用户的输入是字符串,无法与数字进行对比。

类型转换

咦,前面不是定义过了吗, 是的你没看过,RUST支持使用使用过的变量。使用该方法可以进行类型转换。

let guess: u32 = guess.trim().parse().expect("Please type a number!");

猜不中?继续猜!

猜不中?我让你猜中为止,循环,欸。

    // --snip--

    println!("The secret number is: {secret_number}");

    loop {
        println!("Please input your guess.");

        // --snip--

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

等下,这猜中了也停不下来啊。优化一下,在猜中的那一条中加入break退出程序

Ordering::Equal => {
    println!("You win!");
    break;
}

处理一下无效的错误输入,不至于输入一个别的东西就让程序崩溃了。

let guess: u32 = match guess.trim().parse() {
    Ok(num) => num,
    Err(_) => continue,
};

最终程序

大功告成,把随机生成的输出关闭就好啦。

use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
    println!("Guess the number!");

    let secret_number = rand::thread_rng().gen_range(1..=100);

    loop {
        println!("Please input your guess.");

        let mut guess = String::new();

        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}");

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

当当当当

我一下就猜中了,厉害不

下面要开始学习基础了。


文章作者: Enomothem
版权声明: 本博客所有文章除特别声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Enomothem !
  目录