• Rust权威指南之编写一个猜数字游戏


    一. 创建一个新的项目

    使用cargo创建一个项目:

    cargo new guessing_game && cd guessing_game
    
    • 1

    进入项目中有下面这几个文件:

    src
    	main.rs      -> 源文件
    .gitignore	   -> git忽略文件
    Cargo.lock     -> 包含有关您的依赖项的确切信息,它由 Cargo 维护,不需要手动编辑.
    Cargo.toml     -> 描述你的依赖,并由自己编写
    
    • 1
    • 2
    • 3
    • 4
    • 5

    Cargo.toml文件如下:

    [package]
    name = "guessing_game"
    version = "0.1.0"
    edition = "2021"
    
    [dependencies]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    接着看一下main.rs文件内容,Cargo创建项目时会生成一个Hello World的代码

    fn main() {
        println!("Hello, world!");
    }
    
    • 1
    • 2
    • 3

    下面我们执行cargo run命令编译运行:

       Compiling rust-example v0.1.0 (file:///TestProject/guessing_game)
        Finished dev [unoptimized + debuginfo] target(s) in 0.20s
         Running `target/debug/guessing_game`
    Hello, world!
    
    • 1
    • 2
    • 3
    • 4

    二. 处理一次猜测

    猜数字游戏的第一部分会请求用户输入,并检查输入是否满足预期的格式,下面我们开始编写代码:

    use std::io;
    
    fn main() {
        println!("=== 猜数字游戏 ==="); // @1
        println!("> 请输入一个数字: ");
        let mut guess = String::new(); // @2
        io::stdin().read_line(&mut guess).expect("读取失败"); // @3
        println!("> 您猜的是: {}", guess)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    这里稍微解释下,后面文章都会有详细介绍,写过其他语言这个一定还是比较熟悉的:

    • 在@1中println!是一个宏,作用是输出字符串

    • 在@2这一行是定义一个变量,但是我们注意到前面有一个mut的关键字,这个是为了标识变量的可变性;

      这里在举个例子:let foo1 = 5let mut foo2 = 5其中foo1是不可变的,foo2是可变的。

    • 在@3中是引入标准库获取控制台输入的数据。

    其他的就不多介绍了,后续章节都有详细介绍!

    最后我们cargo run编译执行下:

        Finished dev [unoptimized + debuginfo] target(s) in 0.00s
         Running `target/debug/guessing_game`
    === 猜数字游戏 ===
    > 请输入一个数字: 
    78
    > 您猜的是: 78
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    三. 生成一个保密数字

    接着这里我们需要生成一个随机数字,作为保密数字,这里需要使用cargo的一个包:rand

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

    添加完之后需要执行cargo build安装下包,如果有IDEA的话,点下图这个位置也可以。

    接着看一下代码里面如何使用:

    // 0.8.5版本的gen_range写法和原来不一样,需要注意下
    let secret_number: i32 = rand::thread_rng().gen_range(1..101);
    println!("加密数字在1-101之间产生: {}", secret_number);
    
    • 1
    • 2
    • 3

    四. 比较猜测数字与保密数字

    接着我们需要比较用户猜的数字和随机生成的保密数字是否一致

    use std::cmp::Ordering;
    use std::io;
    use rand::Rng;
    
    fn main() {
        let secret_number = rand::thread_rng().gen_range(1..101);
        println!("加密数字在1-101之间产生: {}", secret_number);
        println!("=== 猜数字游戏 ===");
        println!("> 请输入一个数字: ");
        let mut guess = String::new(); // @1
        io::stdin().read_line(&mut guess).expect("读取失败");
        let guess: i32 = guess.trim().parse().expect("请输出正确的格式"); // @2
        match guess.cmp(&secret_number) { // @3
            Ordering::Less => println!("> 您猜的是: {}, 太小", guess),
            Ordering::Greater => println!("> 您猜的是: {}, 太大", guess),
            Ordering::Equal => println!("> 您猜的是: {}, 正确", guess)
        };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这里的@1我们是通过String字符串进行接收用户输入的,但是保密数字是i32类型的,如果cmp比较会报类型错误,所以@2进行类型转换,trim函数是将字符前后的空格去掉,最后在@3使用模式匹配进行比较。

    Ordering是一个枚举:

    #[derive(Clone, Copy, Eq, Debug, Hash)]
    #[stable(feature = "rust1", since = "1.0.0")]
    #[repr(i8)]
    pub enum Ordering {
        /// An ordering where a compared value is less than another.
        #[stable(feature = "rust1", since = "1.0.0")]
        Less = -1,
        /// An ordering where a compared value is equal to another.
        #[stable(feature = "rust1", since = "1.0.0")]
        Equal = 0,
        /// An ordering where a compared value is greater than another.
        #[stable(feature = "rust1", since = "1.0.0")]
        Greater = 1,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    最后编译执行:

        Finished dev [unoptimized + debuginfo] target(s) in 0.01s
         Running `target/debug/guessing_game`
    加密数字在1-101之间产生: 78
    === 猜数字游戏 ===
    > 请输入一个数字: 
    12
    > 您猜的是: 12, 太小
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    五. 使用循环来实现多次猜测

    上面我们直接输入数字比较之后直接输出结果就结束了,下面我们使用loop关键字,实现可以多次猜测。

    use std::cmp::Ordering;
    use std::io;
    use rand::Rng;
    
    fn main() {
        let secret_number = rand::thread_rng().gen_range(1..101);
        println!("加密数字在1-101之间产生: {}", secret_number);
        loop { // @1
            println!("=== 猜数字游戏 ===");
            println!("> 请输入一个数字: ");
            let mut guess = String::new();
            io::stdin().read_line(&mut guess).expect("读取失败");
            let guess: i32 = guess.trim().parse().expect("请输出正确的格式");
            match guess.cmp(&secret_number) {
                Ordering::Less => println!("> 您猜的是: {}, 太小", guess),
                Ordering::Greater => println!("> 您猜的是: {}, 太大", guess),
                Ordering::Equal => { // @2
                    println!("> 您猜的是: {}, 正确", guess);
                    break;
                }
            };
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    增加loop关键字,可以实现类似while(true){}功能,另切在@2中如果猜对了,可以使用break跳出循环。

    六. 处理非法输入

    当我们输入一些非法的字符,可能会导致系统奔溃,如下:

        Finished dev [unoptimized + debuginfo] target(s) in 0.01s
         Running `target/debug/guessing_game`
    加密数字在1-101之间产生: 26
    === 猜数字游戏 ===
    > 请输入一个数字: 
    ttt
    thread 'main' panicked at '请输出正确的格式: ParseIntError { kind: InvalidDigit }', src/main.rs:13:47
    stack backtrace:
       ......
    note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    下面我们再使用模式匹配的match处理下异常情况continue,不要让其程序崩溃。

    use std::cmp::Ordering;
    use std::io;
    use rand::Rng;
    
    fn main() {
        let secret_number = rand::thread_rng().gen_range(1..101);
        println!("加密数字在1-101之间产生: {}", secret_number);
        loop {
            println!("=== 猜数字游戏 ===");
            println!("> 请输入一个数字: ");
            let mut guess = String::new();
            io::stdin().read_line(&mut guess).expect("读取失败");
            let guess: i32 = match guess.trim().parse() {
                Ok(num) => num,
                Err(_) => continue
            };
            match guess.cmp(&secret_number) {
                Ordering::Less => println!("> 您猜的是: {}, 太小", guess),
                Ordering::Greater => println!("> 您猜的是: {}, 太大", guess),
                Ordering::Equal => {
                    println!("> 您猜的是: {}, 正确", guess);
                    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

    编译执行,看一下结果:

        Finished dev [unoptimized + debuginfo] target(s) in 0.01s
         Running `target/debug/guessing_game`
    加密数字在1-101之间产生: 85
    === 猜数字游戏 ===
    > 请输入一个数字: 
    12
    > 您猜的是: 12, 太小
    === 猜数字游戏 ===
    > 请输入一个数字: 
    ttt
    === 猜数字游戏 ===
    > 请输入一个数字: 
    85
    > 您猜的是: 85, 正确
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
  • 相关阅读:
    【计算机组成原理】指令系统(一)—— 指令格式
    【机器学习】基础篇--线代基础
    在线负载离线负载与在线算法离线算法
    地形系统-unity3D地形的生成原理和地形表面贴图的混刷原理
    京东商品详情API:电商创新的利器
    异常校验处理
    AVR单片机开发1——IO口的输入和输出
    施展世界:GPT时代需要的教育,是学会如何提出好问题
    55. 跳跃游戏
    Mybatis-plus如何快速实现动态数据源切换?
  • 原文地址:https://blog.csdn.net/yhflyl/article/details/127773999