第2章 Rust初体验6/8:Option枚举及其变体:能避免空指针异常问题:猜骰子冷热游戏

发布于:2024-06-18 ⋅ 阅读:(18) ⋅ 点赞:(0)

讲动人的故事,写懂人的代码

2.6 故事4: 一直让玩家不断猜

我们全班要一起用三种语言来写第4个故事啦。这可能是我们所有故事中最复杂的一个了。不过别担心,贾克强已经把这个故事的需求都用投影仪展示出来了。

  • 程序会提示玩家猜两个骰子的点数之和。
  • 如果玩家第一次输入点数之和就答错了,程序就会提示‘第一次猜就错了哦’(You guessed it wrong on the first try.),并让玩家继续猜。
  • 如果玩家第二次或之后输入点数之和也答错了,但这次猜测比上次更接近正确答案,程序就会提示‘更热了’(Hotter.),并让玩家继续猜。
  • 如果离正确答案更远了,程序就会提示‘更冷了’(Colder.),并让玩家继续猜。
  • 如果距离正确答案的距离和上次一样,程序就会提示‘不冷不热’(Neither cold nor hot.),并让玩家继续猜。
  • 如果玩家猜对了,程序就会提示‘恭喜你答对了!’(You win!),并让玩家继续猜。

贾克强:“故事4对于Rust新手来说,可能有些挑战性。但别担心,这个故事,我来帮你们写Rust代码哦。”

2.6.1 Rust版故事4

2.6.1.1 初始化 previous_guess

贾克强:“故事4是让玩家不断地猜测,所以我们把原来只猜一次的代码,放入了一个循环中。这样一来,就不需要原来猜一次的代码了。“

”然后,我们新增了一行代码。为了能判断玩家的猜测是否接近答案,我们增加了一个previous_guess变量来存储玩家的上一次猜测。在玩家第一次猜测之前,previous_guess变量的值应该为空。但是,一旦玩家猜了第一次,这个变量就不会再是空的。因此,我们为这个变量使用了Option<u32>类型。这意味着previous_guess既可以是一个u32的32位无符号整数(表示玩家猜测的点数),也可以是None(表示玩家还没有猜测过)。在Rust中,None是一个枚举值(也就是枚举类型Option<u32>的变体),用来表示‘无效’或‘未设置’。“

-    println!("Please input your guess (between 2 and 12).");
-
-    let mut guess = String::new();
-
-    io::stdin()
-        .read_line(&mut guess)
-        .expect("Failed to read line");
-
-    let guess: u32 = guess.trim().parse().expect("Please type a number!");
-
-    println!("You guessed: {guess}");
-
-    match guess.cmp(&sum_of_two_dice) {
-        Ordering::Less | Ordering::Greater => println!("You guessed it wrong on the first try"),
-        Ordering::Equal => println!("You win!"),
-    }
+    let mut previous_guess: Option<u32> = None;

2.6.1.2 增加循环结构

贾克强:“我们在这里添加了一个loop循环,让代码能够反复进行玩家的输入和猜测。loop在Rust中是一个无尽的循环,但别担心,我们在后面的故事中,可以使用break语句来结束它哦!”

+    loop {

2.6.1.3 获取玩家输入

贾克强:“这部分代码和原代码有些相似,它们都是把玩家的输入读取出来,然后解析成u32类型的整数哦。”

+        println!("Please input your guess (between 2 and 12).");
+
+        let mut guess = String::new();
+
+        io::stdin()
+            .read_line(&mut guess)
+            .expect("Failed to read line");
+
+        let guess: u32 = guess.trim().parse().expect("Please type a number!");
+
+        println!("You guessed: {guess}");

2.6.1.4 新的比较逻辑

贾克强兴奋地解释道:“这里,我们新增了对previous_guess的检查哦。如果previous_guessNone(也就是说这是我们的第一次猜测),我们就直接将当前的猜测和骰子的和进行比较。若玩家第一次猜得不对,那我们就会把当前的猜测存入previous_guess中。”

他继续说:“Some(guess)的意思是,我们把guess封装在一个Some枚举中,并赋值给previous_guess,这样previous_guess保存的值就从None变成了Some(guess)。这就意味着,previous_guess不再是空的了,而是包含了玩家上一次的猜测值哦。”

+        match previous_guess {
+            None => match guess.cmp(&sum_of_two_dice) {
+                Ordering::Less | Ordering::Greater => {
+                    println!("You guessed it wrong on the first try.");
+                    previous_guess = Some(guess);
+