• 用Rust写个猜数字的游戏(详解)


    我的学习总结

    简单输入

    1. 建项目,使用cargo的new命令,创建一个guess_number目录
     cargo new guess_number
     cd guess*
     code .
    
    • 1
    • 2
    • 3


    2. 构造项目

    cargo build
    
    • 1

    在这里插入图片描述
    在这里插入图片描述
    3. 处理用户输入

    use std::io;
    
    fn main() {
        println!("---猜数字游戏---");
        println!("请输入你猜的数字: ");
        //生成一个String类型的字符串
        let mut guess=String::new();
        io::stdin().read_line(&mut guess).expect("输入错误\n");
        println!("你输入的数字是: {}",guess);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    解析:

    • println! :表示输出的一个宏括号里填上要输出的内容
    • let mut 变量 :表示生成一个可变的变量,mut表示可变(mutable),如果没有加 mut,则表示变量是只读的,无法修改
    • String::new() :生成一个空的字符串,表示创建一个变量,用于以后的输出
    • io::stdin() :表示要进行io读取,即要从缓冲区读取内容,主要要在前面加上 use std::io ,表示加入io这个空间。
    • read_Line(&mut guess) :表示将要读取一行,中间的内容要填写为变量取地址,相当于指针,要读取对象的地址才能修改变量,别忘了加上mut可变的修饰符
    • expect() :返回枚举类型,Ok和Err,如果前面的读取出错了,返回Err,则打印括号里的内容,并停止,如果输入正确,返回Ok,什么都不错
    • {} :表示将要输出的变量,是一个占位符
    1. 简单测试
    cargo run
    
    • 1

    在这里插入图片描述

    生成一个随机的数字

    接下来,需要生成一个秘密数字,好让用户来猜。秘密数字应该每次都不同,这样重复玩才不会乏味;范围应该在 1 到 100 之间,这样才不会太困难。Rust 标准库中尚未包含随机数功能。然而,Rust 团队还是提供了一个包含上述功能的 :rand
    rand下载地址
    导入rand扩展包:
    在Cargo.toml文件的下面,添加这样一行信息:(表示我们要下载rand的扩展包的0.8.5版本,当然你可以根据网站的信息来下载最新的)

    rand=“0.8.5”
    在这里插入图片描述

    我们来重新构建一下

    cargo build
    
    • 1

    在这里插入图片描述
    稍微等待一下,就可以根据你填写的版本,下载rand扩展包,此时构建完成之后,Cargo.lock文件里就会生成rand的相关信息配置,此时我们的rand就配置成功了,如果你想修改版本,直接在Cargo.toml里面修改rand的版本号就可以,然后重新执行 cargo build 来构建它。

    下面我们来生成一个随机数字:

    1. 导入rand的Rng
    use rand::Rng;
    
    //生成一个随机数字
    let secret_number=rand::thread_rng().gen_range(1..101);
    
    • 1
    • 2
    • 3
    • 4

    注意我们生成的随机数字是不变的,所以不用给它声明为mut,后面照抄就可以(以后再讲),注意gen_raneg的括号里面的格式:
    1…101;表示生成一个左闭右开的区间: [1,101) ;
    1…=101:表示生成一个左闭右闭的区间,[1,101]

    1. 显示随机数字
    use std::io;
    use rand::Rng;
    
    fn main() {
        println!("---猜数字游戏---");
    
        //生成一个随机数字
        let secret_number=rand::thread_rng().gen_range(1..101);
    
        println!("请输入你猜的数字: ");
        //生成一个String类型的字符串
        let mut guess=String::new();
        io::stdin().read_line(&mut guess).expect("输入错误\n");
        println!("你输入的数字是: {}",guess);
    
        println!("随机数字是:{}",secret_number);
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    cargo run
    
    • 1

    在这里插入图片描述

    比较猜测数字与神秘数字

    你可能认为,if else可以轻松的解决这个问题,但是在rust里面我们无法使用if else(就我目前而言不知道),我们要了解一个新的东西: macth(匹配)
    导入一个叫做cmp的东西

    use std::cmp::Ordering;
    
    //匹配 guess和secret_number是什么类型
     match guess.cmp(&secret_number) {
            Ordering::Less => println!("Too small.\n"),
            Ordering::Greater => println!("Too big.\n"),
            Ordering::Equal => println!("Equal.\n"),
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    但是现在我们还不能编译他,会出错,我们先了解以下这个结构:

    • 首先我们增加了另一个 use 声明,从标准库引入了一个叫做 std::cmp::Ordering 的类型到作用域中。 Ordering 也是一个枚举,不过它的成员是 Less、Greater 和 Equal。这是比较两个值时可能出现的三种结果。
    • 简单来说cmp返回枚举Less,Greate,Equal中的值,
    • guess和secret_number如果Less:小于,则打印,最后带一个break
    • guess和secret_number如果Equal:相等,则打印,break
    • guess和secret_number如果Greate:大于,则打印,break
    • 类似于C/C++的switch语句,匹配选择打印

    但是我们忘记了一个很重要的东西:
    先试着来编译以下:

    cargo run
    
    • 1

    在这里插入图片描述
    String不是整形,不能和随机生成的数字相比较,类型不匹配,所以我们必须试着转换类型

    shadow隐藏与类型转换

    在这里插入图片描述
    guess 是 String类型
    secret_number是i32类型
    我们可以使用rust提供的一个新概念:隐藏(shadow)

    //shadow隐藏
       let guess:u32=guess.trim().parse().expect("转换失败!\n");
    
    • 1
    • 2

    简单来说,当我们在下文创建一个同名的变量时,会自动隐藏上一个同名的变量,我们把以前的这个String类型转换为 u32类型。需要显示指定类型。

    • trim :会去除字符串开头和结尾的空白字符
    • parse:会转换为合适的指定的类型: u32

    之后我们的guess就从String变成了 u32类型,同时上一个guess的String类型就会消失
    这时我们就用match同时对两个 u32类型的数进行比较了。

    注意:match的cmp会自动强制转化两个变量为同一类型:
    在这里插入图片描述
    secret一开始是 i32类型,生成的随机数,是有符号整型,会自动转换为和guess一样的类型: u32
    然后就可以比较了,运行如下:

    cargo run
    
    • 1

    在这里插入图片描述

    循环程序

    我们已经完成了这个程序的大部分,猜数字还应该持续的比较下去,直到你猜到了随机数字:使用loop循环来进行游戏重复进行:
    类似于 while(1) 注意,它是无限循环,需要指定游戏的退出

    loop {
            println!("请输入你猜的数字: ");
            //生成一个String类型的字符串
            let mut guess=String::new();
            io::stdin().read_line(&mut guess).expect("输入错误\n");
    
            //shadow隐藏
            let guess:u32=guess.trim().parse().expect("转换错误!\n");
    
            println!("你输入的数字是: {}",guess);
    
            match guess.cmp(&secret_number) {
                Ordering::Less => println!("Too small.\n"),
                Ordering::Greater => println!("Too big.\n"),
                Ordering::Equal => break,   //游戏结束
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    注意要在比较时相等的情况下,指定它退出loop循环,即break
    别忘了隐藏随机数字,不打印出来随机数字。
    运行程序如下:

    cargo run
    
    • 1

    在这里插入图片描述

    处理无效输入

    我们还剩最后一步,我们如果在输入数字时出现了字母或者其他字符该怎么办?
    在这里插入图片描述
    程序就会直接退出,报错
    在变量隐藏和强制转换的时候,指定出错误时需要干的事情:即重新读取

     //shadow隐藏
            let guess:u32=match guess.trim().parse()
            {
                Ok(num) => num,
                Err(_) => continue,
            };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    别忘了parse的返回类型是Result类型,是一个枚举类型,返回Ok,或者Err

    • Ok: 正确,则这个数字就是这个数字
    • Err : 错误,将 ‘_’ 作为占位符,接着continue要求重复输入

    最后我们再来运行一下程序:

    cargo run
    
    • 1

    在这里插入图片描述
    这样我们就算输入字符也会提示我们重新输入

    这样我们的猜数字游戏就完成了

    完整代码

    use std::io;
    use rand::Rng;
    use std::cmp::Ordering;
    
    fn main() {
        println!("---猜数字游戏---");
    
        //生成一个随机数字
        let secret_number=rand::thread_rng().gen_range(1..101);
    
        loop {
            println!("请输入你猜的数字: ");
            //生成一个String类型的字符串
            let mut guess=String::new();
            io::stdin().read_line(&mut guess).expect("输入错误\n");
    
            //shadow隐藏
            let guess:u32=match guess.trim().parse()
            {
                Ok(num) => num,
                Err(_) => continue,
            };
    
            println!("你输入的数字是: {}",guess);
    
            match guess.cmp(&secret_number) {
                Ordering::Less => println!("Too small.\n"),
                Ordering::Greater => println!("Too big.\n"),
                Ordering::Equal => 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

    这一期只是先了解一下rust语言,如果有什么不懂的函数或者其他的东西,其实我也不懂,今后我们将一步步来讲解这些东西
    下期预告:常见rust编程概念: 基本变量和标量函数注释

  • 相关阅读:
    Gin框架快速入门教程
    图生成数据集
    万字解析:十大排序(直接插入排序+希尔排序+选择排序+堆排序+冒泡排序+快速排序+归并排序+计数排序+基数排序+桶排序)
    CTF是黑客大赛?新手如何入门CTF?
    搭建selenium环境
    C语言每日一题(10) 回形矩阵
    【C++】仿函数
    【EI会议征稿通知】第十届能源材料与环境工程国际学术会议(ICEMEE 2024)
    Android JNI HIDL 简单实例学习
    dart的Websocket为什么找不到onOpen方法?
  • 原文地址:https://blog.csdn.net/jj6666djdbbd/article/details/126813828