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

文章目录

    • 简单输入
    • 生成一个随机的数字
    • 比较猜测数字与神秘数字
    • shadow隐藏与类型转换
    • 循环程序
    • 处理无效输入
    • 完整代码

我的学习总结

简单输入

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

用Rust写个猜数字的游戏(详解)_第1张图片
2. 构造项目

cargo build

在这里插入图片描述
用Rust写个猜数字的游戏(详解)_第2张图片
3. 处理用户输入

use std::io;

fn main() {
    println!("---猜数字游戏---");
    println!("请输入你猜的数字: ");
    //生成一个String类型的字符串
    let mut guess=String::new();
    io::stdin().read_line(&mut guess).expect("输入错误\n");
    println!("你输入的数字是: {}",guess);
}

解析:

  • 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

用Rust写个猜数字的游戏(详解)_第3张图片

生成一个随机的数字

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

rand=“0.8.5”
用Rust写个猜数字的游戏(详解)_第4张图片

我们来重新构建一下

cargo build

用Rust写个猜数字的游戏(详解)_第5张图片
稍微等待一下,就可以根据你填写的版本,下载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);

注意我们生成的随机数字是不变的,所以不用给它声明为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);
}

cargo run

用Rust写个猜数字的游戏(详解)_第6张图片

比较猜测数字与神秘数字

你可能认为,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"),
    }

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

  • 首先我们增加了另一个 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

用Rust写个猜数字的游戏(详解)_第7张图片
String不是整形,不能和随机生成的数字相比较,类型不匹配,所以我们必须试着转换类型

shadow隐藏与类型转换

用Rust写个猜数字的游戏(详解)_第8张图片
guess 是 String类型
secret_number是i32类型
我们可以使用rust提供的一个新概念:隐藏(shadow)

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

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

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

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

注意:match的cmp会自动强制转化两个变量为同一类型:
用Rust写个猜数字的游戏(详解)_第9张图片
secret一开始是 i32类型,生成的随机数,是有符号整型,会自动转换为和guess一样的类型: u32
然后就可以比较了,运行如下:

cargo run

用Rust写个猜数字的游戏(详解)_第10张图片

循环程序

我们已经完成了这个程序的大部分,猜数字还应该持续的比较下去,直到你猜到了随机数字:使用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,   //游戏结束
        }
    }

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

cargo run

用Rust写个猜数字的游戏(详解)_第11张图片

处理无效输入

我们还剩最后一步,我们如果在输入数字时出现了字母或者其他字符该怎么办?
用Rust写个猜数字的游戏(详解)_第12张图片
程序就会直接退出,报错
在变量隐藏和强制转换的时候,指定出错误时需要干的事情:即重新读取

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

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

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

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

cargo run

用Rust写个猜数字的游戏(详解)_第13张图片
这样我们就算输入字符也会提示我们重新输入

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

完整代码

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,   //游戏结束
        }
    }

}

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

你可能感兴趣的:(rust,rust,游戏,开发语言)