通过编写一个简单的游戏学习 Rust

通过一个你可以用多种语言尝试的简单游戏开始编程。
47 位读者喜欢这篇文章。
Ferris the crab under the sea, unofficial logo for Rust programming language

Opensource.com

当你想学习一门新的编程语言时,最好专注于编程语言的共同之处

  • 变量
  • 表达式
  • 语句

这些概念是大多数编程语言的基础。一旦你理解了它们,你就可以开始弄清楚其余的部分。

因为编程语言通常具有相似之处,所以一旦你掌握了一种语言,你就可以通过理解其差异来学习另一种语言的基础知识。

学习新语言的一个好方法是使用一个你可以用来练习的标准程序。这使你可以专注于语言本身,而不是程序的逻辑。在本系列文章中,我正在使用一个“猜数字”程序来做到这一点,在这个程序中,计算机会选择一个 1 到 100 之间的数字,并要求你猜这个数字。程序会循环,直到你猜对数字为止。

这个程序练习了编程语言中的几个概念

  • 变量
  • 输入
  • 输出
  • 条件评估
  • 循环

这是一个学习新编程语言的绝佳实践实验。

安装 Rust

你可以使用 Rustup 安装 Rust 工具链,或者你可以在线试用 Rust,而无需在本地安装。

如果你在本地安装了 Rust,你应该定期使用 rustup update 更新它,以保持你的工具链最新,并使用 cargo update 更新你的库到最新版本。

用 Rust 猜数字

Rust 是一种使任何人都能构建可靠且高效软件的语言。你可以通过编写一个“猜数字”游戏的版本来探索 Rust。

第一步是编写一个 Cargo.toml 文件。你可以使用 cargo new 命令生成一个 Cargo.toml 骨架。这几乎总是启动 Rust 项目的最佳方式。

$ cargo new guess
$ cd guess
$ ls -1
Cargo.toml 
src/

Cargo.toml 文件命名你的包,为其提供一些元数据,最重要的是,指定它依赖于 rand crate

[package]
name = "guess"
version = "2020.11.0"
authors = ["Moshe Zadka <moshez@opensource.com>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.net.cn/cargo/reference/manifest.html

[dependencies]
rand = "*"

Rust 中的许多东西都不是由语言或标准库提供的。相反,你可以从许多外部 crate 中获得它们,这些 crate 可以完成许多事情。

程序逻辑放在 src/main.rs

use rand::Rng;
use std::io::BufRead;

fn main() {
    let mut rng = rand::thread_rng();
    let random = rng.gen_range(1..101);
    println!("Guess a number between 1 and 100");
    for line in std::io::stdin().lock().lines() {
        let parsed = line.ok().as_deref().map(str::parse::<i64>);
        if let Some(Ok(guess)) = parsed {
            match guess {
                _ if guess < random => println!("Too low"),
                _ if guess > random => println!("Too high"),
                _ => {
                    println!("That's right");
                    break;
                }
            }
        }
    }
}

代码的前两行声明了你要做什么。在本例中,rand::Rng 生成一个猜测,而 trait std::io::BufRead 允许从标准输入读取。

Rust 代码的入口点在 main() 函数中,所以下一步是定义 main()

要为变量赋值,请使用 let,然后是变量的名称,后跟 = 符号。这将创建一个不可变变量。

你的大多数变量将是不可变的,但 rng 对象必须是可变的。例如,语句 let random = 0 将零值赋给 random 变量。

函数的第一行创建一个线程安全的 Rng 对象,并将其赋值给变量 rng。Rust 构建于线程和内存安全之上,因此你必须在开始编写代码时就考虑这些事情。

程序的下一行读取函数 gen_range() 的结果,并将其赋值给名为 random 的变量。该函数接受一个最小值(包含)和一个上限(不包含)。为了使上限包含在内,你可以用等号标记较大的数字(例如,1..=100),或者你可以像我在代码中所做的那样,将上限设置为比你的预期最大值高 1。在本例中,范围是 1100,使游戏具有足够的挑战性。

中心循环遍历 std::io::stdin() 中的行。由于可能存在各种可能导致行无法读取的极端情况,Rust 要求你使用 Result 包装一行。行也可能无法解析为整数。

此代码使用条件模式匹配来忽略所有可能导致错误的行

        let parsed = line.ok().as_deref().map(str::parse::<i64>);
        if let Some(Ok(guess)) = parsed {
            // ...
        }

第一行创建一个 Result<Option<i64>, ...> 对象,因为它可能在读取或解析步骤中失败。由于下一行仅匹配 Some(Ok(guess)),因此每当一行产生不匹配的值时,它都会跳过 if 语句。这是一种忽略错误的强大方法。

Rust 支持条件表达式和流程控制,例如循环。在“猜数字”游戏中,只要猜测值不等于 random,Rust 就会继续循环。

if 语句的主体包含使用 Rust 的 match 语句的三向分支。虽然 match 最常用于模式匹配,但它也可以检查任意条件。在这种情况下,如果猜测正确,则打印适当的消息并 break 循环。

示例输出

现在你已经编写了你的 Rust 程序,你可以运行它来玩“猜数字”游戏。每次你运行程序时,Rust 都会选择一个不同的随机数,所以继续猜测直到你找到正确的数字

$ cargo run
   Compiling guess v2020.11.0 (/Users/mzadka/src/guess)
    Finished dev [unoptimized + debuginfo] target(s) in 0.70s
     Running `target/debug/guess`
Guess a number between 1 and 100
50
Too high
25
Too high
12
Too low
18
Too high
15
Too high
13
Too low
14
That's right

通常通过运行 cargo run 来测试程序。最终,你可能会使用 cargo build构建可执行文件并将其作为两个独立的步骤运行

学习 Rust

“猜数字”游戏是学习新编程语言的一个很好的入门程序,因为它以一种非常直接的方式练习了几个常见的编程概念。通过用不同的编程语言实现这个简单的游戏,你可以展示这些语言的一些核心概念,并比较它们的细节。

你有没有最喜欢的编程语言?你会用它怎么编写“猜数字”游戏?关注本系列文章,了解其他你可能感兴趣的编程语言的示例!

接下来阅读
标签
Moshe sitting down, head slightly to the side. His t-shirt has Guardians of the Galaxy silhoutes against a background of sound visualization bars.
Moshe 自 1998 年以来一直参与 Linux 社区,帮助举办 Linux “安装派对”。他自 1999 年以来一直在编写 Python 代码,并为核心 Python 解释器做出了贡献。Moshe 在这些术语出现之前就一直是 DevOps/SRE,他非常关心软件可靠性、构建可重现性以及其他此类事情。

2 条评论

嗨,感谢这篇有用的文章!

我的代码在第 7 行遇到了错误
`rng.gen_range(1, 100+1)` 必须更改为 `rng.gen_range(1..101)`
(使用全新的 Rust 安装,这是我第一次尝试这门语言)

另外,你能否更详细地解释一下第 10 行:`Some(Ok(guess)) = parsed` 吗?这对我来说相当晦涩难懂...

gen_range 最近从 X,Y 更改为 X..Y 语法 (https://docs.rs/rand/0.8.0/rand/trait.Rng.html#method.gen_range)。我全新安装的 Rust 工具链,就像本文中的一样,也使用了 X,Y 语法。

cargo 1.48.0 (65cbdd2dc 2020-10-14)

在执行 `cargo update` 之后,0.8.0 版本的 gen_range 被拉入,代码中断,需要你提到的更改。

我已经更新了 Moshe 的文章以反映这些更改。感谢你的提醒!

回复 作者:erralb

Creative Commons License本作品根据 Creative Commons Attribution-Share Alike 4.0 International License 许可。
© . All rights reserved.