• 【Rust 入门学习】2.1 Rust 猜谜游戏


    猜谜游戏

    在深入学习 rust 之前,先通过一个简单的小游戏练练手。

    实现一个经典的初学者编程问题:猜谜游戏。

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

    新建项目

    进入目录并使用 Cargo 创建一个新项目

    cd ~/projects
    cargo new guessing_game
    cd guessing_game
    
    • 1
    • 2
    • 3

    目录文件结构和内容和上一章节介绍的一样只是项目名变了而已

    编译运行它,依旧是一个 helloword 。

    $ cargo run
       Compiling guessing_game v0.1.0 (/home/mshing/projects/guessing_game)
        Finished dev [unoptimized + debuginfo] target(s) in 4.07s
         Running `target/debug/guessing_game`
    Hello, world!
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在后续的练习中,直接使用 run 命令来进行测试版本迭代,无需每次都编译。

    处理猜想

    猜谜游戏程序的第一部分将要求用户输入,处理该输入,并检查输入是否符合预期形式。首先,我们将允许玩家输入猜测。

    文件名:src/main.rs

    use std::io;
    
    fn main() {
        println!("猜猜数字!");
    
        println!("请输入你猜到的数字:");
    
        let mut guess = String::new();
    
        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");
    
        println!("你猜对了: {guess}");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这段代码不长,但是信息挺多的。

    首先看第一行,因为要获取用户的输入然后将结果打印出来,就需要将 io 输入、输出导入代码中。

    io库来自标准库,称为std

    use std::io;
    
    • 1

    可以在标准库文档中看到其中的所有内容。

    下面是main函数是程序的入口:

    fn main() {
    
    • 1

    fn语法声明了一个新函数,括号 ,表示()没有参数,大括号{, 开始函数体。

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

        println!("Guess the number!");
    
        println!("Please input your guess.");
    
    • 1
    • 2
    • 3

    此代码正在打印一个提示,说明游戏是什么并请求用户输入。

    再下一行是创建一个用来存储用户输入信息的变量:

        let mut guess = String::new();
    
    • 1

    存储用户输入的信息

    从模块 io 中调用 stdin 函数,这允许我们处理用户输入:

        io::stdin()
            .read_line(&mut guess)
    
    • 1
    • 2

    如果我们没有在程序开头导入 iouse std::io ,我们仍然可以通过将此函数调用编写为 std::io::stdin

    Result使用类型处理潜在故障

            .expect("Failed to read line");
    
    • 1

    我们可以把这段代码写成:

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

    但是,一长行很难阅读,因此最好将其分开。

    更多的相关知识后面章节介绍。

    println!使用占位符打印值

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

    运行测试

    $ cargo run
       Compiling guessing_game v0.1.0 (/home/mshing/projects/guessing_game)
        Finished dev [unoptimized + debuginfo] target(s) in 0.48s
         Running `target/debug/guessing_game`
    猜猜数字!
    请输入你猜到的数字:
    12
    你猜对了: 12
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    到这里完成第一部分:从键盘输入,然后打印出来。

    生成秘密数字

    接下来,将生成一个用户猜测的秘密数字,它是1到100之间的随机数。

    Rust 的标准库中还没有包含随机数功能,但是有一个类似功能的 rand crate 函数可以使用。

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

    需要修改Cargo.toml文件以包含randcrate 作为依赖项

    文件名:Cargo.toml

    [dependencies]
    rand = "0.8.5"
    
    • 1
    • 2

    编译项目

    $ cargo build
      Downloaded ppv-lite86 v0.2.16 (registry `tuna`)
      Downloaded cfg-if v1.0.0 (registry `tuna`)
      Downloaded getrandom v0.2.7 (registry `tuna`)
      Downloaded rand v0.8.5 (registry `tuna`)
      Downloaded rand_core v0.6.3 (registry `tuna`)
      Downloaded rand_chacha v0.3.1 (registry `tuna`)
      Downloaded libc v0.2.126 (registry `tuna`)
      Downloaded 7 crates (773.8 KB) in 4.92s
       Compiling libc v0.2.126
       Compiling cfg-if v1.0.0
       Compiling ppv-lite86 v0.2.16
       Compiling getrandom v0.2.7
       Compiling rand_core v0.6.3
       Compiling rand_chacha v0.3.1
       Compiling rand v0.8.5
       Compiling guessing_game v0.1.0 (/home/mshing/projects/guessing_game)
        Finished dev [unoptimized + debuginfo] target(s) in 10.16s
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    当我们包含一个外部依赖项时,Cargo 会从注册表中获取依赖项所需的所有内容的最新版本,该注册表是来自Crates.io的数据副本。Crates.io 是 Rust 生态系统中的人们发布他们的开源 Rust 项目供其他人使用的地方。

    官方源速度太慢,文中的源已经换成国内的清华大学源了。

    生成随机数

    使用刚才引入的 rand 依赖创建随机数

    文件名:src/main.rs

    use std::io;
    use rand::Rng;
    
    fn main() {
        println!("猜猜数字!");
    
        let secret_number = rand::thread_rng().gen_range(1..=100);
    
        println!("谜底数字是:{secret_number}");
    
        println!("请输入你猜到的数字(1-100):");
    
        let mut guess = String::new();
    
        io::stdin()
            .read_line(&mut guess)
            .expect("Failed to read line");
    
        println!("你猜对了: {guess}");
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    添加行use rand::Rng。该Rng特征定义了随机数生成器实现的方法,我们使用他定义生成(1-100)之间的随机整数。

    对于打印出最后的谜底数字是好随时调试程序,最终是需要删除的,如果一开始就知道答案,那肯定就没法玩了。

    多运行几次程序,可以看到随机数据:

    $ cargo run
       Compiling guessing_game v0.1.0 (/home/mshing/projects/guessing_game)
        Finished dev [unoptimized + debuginfo] target(s) in 2.57s
         Running `target/debug/guessing_game`
    猜猜数字!
    谜底数字是:78
    请输入你猜到的数字(1-100)7
    你猜对了: 7
    
    $ cargo run
        Finished dev [unoptimized + debuginfo] target(s) in 0.01s
         Running `target/debug/guessing_game`
    猜猜数字!
    谜底数字是:92
    请输入你猜到的数字(1-100)4
    你猜对了: 4
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    循环对比输入数字和谜底数字

    首先,我们添加另一个use语句,将标准库中调用的类型 std::cmp::Ordering引入范围。该Ordering类型是一个枚举,具有 LessGreaterEqual。这是比较两个值时可能出现的三种结果。

    最终程序

    我们新增循环输入直到答案正确为止、判断输入的是不是整数。

    文件名:src/main.rs

    use std::io;
    use rand::Rng;
    use std::cmp::Ordering;
    
    fn main() {
        println!("猜猜数字!");
    
        let secret_number = rand::thread_rng().gen_range(1..=100);
    
        loop {
            println!("请输入你猜到的数字(1-100):");
            let mut guess = String::new();
            io::stdin()
                .read_line(&mut guess)
                .expect("Failed to read line");
    
            println!("你猜的数字是: {guess}");
    
            let guess: u32 = match guess.trim().parse() {
                Ok(num) => num,
                Err(_) => {
                    println!("请确保输入的是数字,且范围是1到100的整数!");
                    continue;
                }
            };
    
            match guess.cmp(&secret_number) {
                Ordering::Less => println!("太小了!"),
                Ordering::Greater => println!("太大了!"),
                Ordering::Equal => {
                println!("你赢了!") ;
                break;
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    运行结果:

    $ cargo run
        Finished dev [unoptimized + debuginfo] target(s) in 0.01s
         Running `target/debug/guessing_game`
    猜猜数字!
    请输入你猜到的数字(1-100)100
    你猜的数字是: 100
    
    太大了!
    请输入你猜到的数字(1-100)60
    你猜的数字是: 60
    
    太小了!
    请输入你猜到的数字(1-100):
    asd
    你猜的数字是: asd
    
    请确保输入的是数字,且范围是1到100的整数!
    请输入你猜到的数字(1-100)80
    你猜的数字是: 80
    
    你赢了!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    总结

    到这里,已经成功构建了一个猜数字的游戏。

    这个项目介绍了很多 Rust 新概念:let 、match、 外部crate的使用等等。接下来的学习将会详细的了解到这些概念。

  • 相关阅读:
    GD32F303固件库开发(14)----IIC之配置OLED
    机器学习|K邻近(K Nearest-Neighbours)
    python异常及解决方法汇总
    说一说 程序员的代码编辑器比较 vscode source insight vim那些年用过的IDE
    嵌入式C 语言函数宏封装妙招
    Python版A股选股软件源代码,选股系统源代码,实现多种选股策略
    Vue 插槽
    leetcode做题笔记2760. 最长奇偶子数组
    Springboot集成阿里云短信
    Allegro单独更改覆铜焊盘的连接方式
  • 原文地址:https://blog.csdn.net/Magic_Ninja/article/details/126145799