Ice 的博客

用心记录思想

关键字(Keywords)

Rust语言有一个关键字集合,这些关键字预留给语言本使用,和其他大部分语言一样。牢记在心,你不能使用这些单词作为变量名或者函数名。大部分的关键字有其特殊的意义,而且你会用这些关键字来做各种各样的任务在Rust程序里。一些关键词目前没有相应的功能,是为了将来可能添加的功能预留的。可以在Appendix A(https://doc.rust-lang.org/book/appendix-01-keywords.html)查看

猜测正确后退出

让我们增加一个break语句,在用户才对时退出游戏:

src/main.rs

1
2
3
4
5
6
7
8
9
10
11
       // --snip--
match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}

通过在You win!之后增加一行break;,用户猜对了神秘数字之后会退出循环。退出循环也意味着退出程序,因为循环是main最后一部分。

处理无效输入

为了进一步使得游戏表现更好,而不是当用户输入无效数字就崩溃,需要忽略无效输入,让用户继续猜。可以通过修改guess将String转换为u32那部分代码来实现,如Listing 2-5:

src/main.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

// --snip--

io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");

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

println!("You guessed: {}", guess);

// --snip--

Listing 2-5 Ignoring a non-number guess and asking for another guess instead of crashing the program

我们将expect调用换成match语句,以从遇到错误就崩溃变为处理错误。需知parse返回一个Result类型,而Result是一个用于Ok或Err成员的枚举。这里使用的match表达式,和之前处理cmp方法返回Ordering时用的一样。

如果parse不能将字符串转换一个数字,它会返回一个包含更多错误信息的Err。Err值不能匹配第一个match分支的Ok(num)模式,但是会匹配第二个分支Err(_)模式:_是一个通配符值,本例中用来匹配所有的Err值,不管其中有任何信息。所以程序会执行第二个分支的动作,continue 意味着进入loop的下一次循环,请求另一个猜测。这样程序就有效地忽略了parse可能遇到的所有错误!

现在所有的事情都是我们期待的了,让我们试试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ cargo run
Compiling guessing_game v0.1.0 (file:///projects/guessing_game)
Finished dev [unoptimized + debuginfo] target(s) in 4.45s
Running `target/debug/guessing_game`
Guess the number!
The secret number is: 61
Please input your guess.
10
You guessed: 10
Too small!
Please input your guess.
99
You guessed: 99
Too big!
Please input your guess.
foo
Please input your guess.
61
You guessed: 61
You win!

牛逼!再有一个小的修改,就能完成猜数字游戏了:还记得程序依然会打印出秘密数字吗?那个是为了便于测试,但是它破坏游戏性。让我们删掉这个打印语句吧。Listing 2-6是最终版本的代码:

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
35
use rand::Rng;
use std::cmp::Ordering;
use std::io;

fn main() {
println!("Guess the number!");

let secret_number = rand::thread_rng().gen_range(1..101);

loop {
println!("Please input your guess.");

let mut guess = String::new();

io::stdin()
.read_line(&mut guess)
.expect("Failed to read line");

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

println!("You guessed: {}", guess);

match guess.cmp(&secret_number) {
Ordering::Less => println!("Too small!"),
Ordering::Greater => println!("Too big!"),
Ordering::Equal => {
println!("You win!");
break;
}
}
}
}

Listing 2-6 Complete guessing game code

总结

至此,你成功地构建了猜数字游戏。恭喜你!

这个项目是一个通过动手实践,向你介绍了很多Rust新概念:let,match,函数,使用外部crate等等。在接下来的章节中,你将会学习这些概念的细节。第三章介绍大部分程序语言都有的概念,比如变量,数据类型和函数,以及如何在Rust中使用他们。第四章探索所有权(owership),一个特性,使得Rust与其他语言不同的特性。第五章讨论结构体和方法的语法,第六章介绍枚举如何工作。

养成使用Cargo习惯

对于简单的项目,和rustc相比,Cargo不能提供多大的价值,但是对于复杂的项目,安装了很多crates, 它将会证明它的价值所在。让Cargo来协调构建工作会变得容易更多。

即使hello_cargo这么简单的项目,它现在使用了很多你之后的Rust生涯将会用到的使用工具。其实,要在任何已存在的项目上工作时,可以使用如下的命令通过Git拿到代码,移动到你的projects目录,并构建:

1
2
3
$ git clone example.org/someproject
$ cd someproject
$ cargo build

更多关于Cargo详情,请查看Cargo 文档(https://doc.rust-lang.org/cargo/)

总结

对于你的Rust之旅,你已经有一个很棒的开始了!本章你已经学会了如何:

  • 使用rustup安装最新稳定版Rust
  • 更新到新版的Rust
  • 打开本地安装的文档
  • 直接通过rustc编写并运行”Hello,world!”程序
  • 使用Cargo创建并运行项目

是时候通过构建更实质性的程序来熟悉写Rust代码了。所以在Chapter 2,我们将构建一个猜数字的游戏程序。如果你更想从学习Rust常用的编程概念开始,请阅读Chapter 3,接着回来看Chapter 2.

编译和运行是彼此独立的步骤

你刚刚运行了一个新的程序,所以让我们来检查一下这个过程的每一个步骤。

在运行Rust程序之前,你必须通过rustc命令,用Rust编译器来编译这个它,并传入你源代码文件的名字,比如:

1
$ rustc main.rs

如果你有C或者C++的技术背景,你可以视作像gcc 或者clang。在编译成功之后,Rust 会输出一个二进制可执行文件。

对于Linux,macOS和PowerShell on Windows,执行ls的shell命令之后,你就可以看到这个可执行文件。对于Linux,macOS,你可以看到两个文件。对于PowerShell on Windows,你会看到和使用CMD一样的三个文件。

1
2
$ ls
main main.rs

在Windows的CMD,输入命令:

1
2
3
4
$ dir /B %= the /B option says to only show the file names =%
main.exe
main.pdb
main.rs

这显示出以.rs为扩展名的源代码文件和可执行文件(main.exe on Windows, but main on all other platforms),并且,当使用Windows,一个文件包括了debugging信息的.pdb扩展名。到此,你可以开始运行main 或者main.exe文件,如:

1
$ ./main # or .\main.exe on Windows

如果main.rs是你的”Hello,world!”程序,这行将打印出”Hello,world!”到你的屏幕。

如果你更加熟悉动态语言,如Ruby,Python, JavaScript, 你也许不习惯将编译和运行分为两个单独的步骤。Rust是一个预编译(ahead-of-time compiled)语言,代表你可以编译一个程序并且给可执行文件其他人,并且他们可以直接运行,不需要安装Rust。如果你给某人一个a.rb, .py, .js文件,他们需要安装一个Ruby,Python 或者JavaScript 实现(运行环境)。不过这些语言中,只需要一句命令就可以编译和运行程序。所有的事都是语言设计上的取舍。

仅仅使用rustc编译简单程序是没有问题的。但是随着你的项目发展,你会想要管理所有的选项,使得更简单地共享你的代码。接下来,我们将介绍给你一个叫做Cargo的工具,它将帮助你编写真实世界的Rust程序。

本地文档

安装过程包括了将对应Rust版本的文档复制到本地。所以你可以阅读官方文档,也可以通过命令:

1
$ rustup doc

会在浏览器里打开本地文档。

标准库里面的任何一个类型或者函数你不确定的时候,或者你不知道怎么用。使用应用程序编程接口(API)文档来找出答案。

欢迎来到Rust编程语言世界!

不管写的好与差,挖坑先,要不然永远不会开始。

Hello, World!

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

2022计划开始一系列关于学习Rust入门的学习笔记,主要是根据官方的文档入门学习。

Rust程序设计语言能帮助你编写更快,更可靠的软件。在编程语言的设计中,高层工程学和底层控制常常是冲突的。Rust挑战了这种冲突。通过平衡强大的技术能力(powerful technical capacity)和 极好的开发者体验(great developer experience),Rust 可以控制底层的细节(比如内存的使用)但不用忍受传统同类型语言那些困扰。

Rust 已经在证明着自己,对于学习过编程知识的不同水平的开发者来说,如果他们开发大型协同项目都是不错的生产工具。底层的代码容易产生各种不易发现的bugs,在其他编程语言中,要发现这些bugs只能通过广泛的测试和团队中经验丰富的大佬们仔细的评审(review)。在Rust设计中,编译器(compiler)扮演着守门员的角色,它会拒绝包含各种bugs代码的编译。通过编译器的帮忙,开发团队将会把更多的时间用在程序的逻辑上,而不是one day day 地在写bugs与修bugs之间疲于奔命。

0%