ShuiBo'blog

人生若只如初见

嗨,我是水波 (@saber).


君以国士待我,我必国士报之。

rust学习之二

昨天参加团建没有看这些,之后继续补上。开始学习第二章的猜猜看游戏。

猜猜看游戏流程

  1. 生成一个随机数
  2. 输入一个数
  3. 比较输入数与随机数
  4. 如果相等则猜对了,否则继续步骤2

代码

extern crate rand;

use std::io;
use std::cmp::Ordering;
use rand::Rng;

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;
            }
        }
    }
}

解读

直接亮代码来解读吧。

extern

extern crate rand;

声明使用rand外部依赖。

记住crate是一个Rust代码的包。我们正在构建的项目是一个二进制 crate,它生成一个可执行文件。randcrate是一个库crate,库crate可以包含任意能被其他程序使用的代码。

可以理解成每个外部依赖都可以理解为在一个库crate里,所以就需要在依赖前加上它。

rand里面有生成随机数的方法。如何添加此依赖?这时候cargo就派上大用场了。只需要编辑Cargo.toml文件,在你再次build的时候就会自动去下载你需要的依赖。

[dependencies]

rand = "0.3.14"

还能更深层次的理解上一次遇到的Cargo.lock文件,此文件能确保构建可以重现。一个项目会有很多依赖,但是如何来确保每个人的依赖都是一致的呢,lock文件就是为此而生的。Cargo第一次构建项目的时候,会去寻找到符合你的依赖版本,并生成lock文件。之后再构建的时候就会使用lock里指定的文件来构建项目。

use

use std::io;

很多语言都是有使用的use这个关键字,rust也不例外。此处是声明引用std里的io库。std::io 库提供很多 io 相关的功能,比如接受用户输入。

use std::cmp::Ordering;

引入std::cmp::Ordering这个类型,这个类型在调用比较两值方法cmp时会有一个对此类型枚举匹配,LessGreaterEqual

use rand::Rng;

引入Rng这个trait,它定义了随机数生成器应实现的方法;

main

letlet mut

letlet mut都是在定义变量。但是let mut是可变变量,let是不可变变量。感觉这是为了性能做的考虑,在底层的初始化应该是不一样的。

同时在使用引用时,let定义的可以直接使用,let mut定义的也是要加个mut

let a = 1;
add(&a);

let mut b = 1;
add(&mut b);

rand::thread_rng().gen_range(1, 101)

rand依赖里的thread_ran()函数,是随机数生成器。再调用这个生成器里的gen_range方法来生成一个在两参数之间的随机数。这个随机数包含下限但不包含上限。

loop{}

loop实现无限循环。可以使用break退出,continue跳过重新继续。

String::new()

初始化一个string类型的变量。

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

调用io的关联函数stdin,它返回了一个终端标准输入的一个句柄。再使用read_line()函数,回车触发,读取这行内容到引用的可变变量guess

read_line()函数除了复制变量,还会返回一个io::Result。它的成员是OkErr,Ok表示操作成功,内部包含成功时产生的值。Err意味着操作失败,包含失败的前因后果。

我们可以使用expect方法,当返回时Err的时候就抛出,我们事先定义的错误信息。

let guess: u32

rust支持对变量隐藏,用一个新值来隐藏guess之前的值。这个功能常用在需要转换值类型之类的场景,它允许我们复用guess变量的名字,而不是被迫创建两个不同变量,诸如guess_strguess之类。

guess.trim().parse()

比较两个数时,rust自己会对变量进行类型判断。前面为了获取输入,赋值guess为string类型,而随机数则是int类型。直接比较会报guess类型错误,所以需要进行类型转换。将guess转成int,使用parse()能直接string转int。trim函数是为了过滤掉输入时需回车触发导致多出一个回车符。

match {}

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

此处也是上面讲的Resultparse()也是会有一个Result返回。因为使用expect并不是很优雅的输出。

$ ./target/debug/hello_cargo
Guess the number!
The secret number is: 67
Please input your guess.
gg
thread ''main'' panicked at ''Please type a number!: ParseIntError { kind: InvalidDigit }'', /checkout/src/libcore/result.rs:906:4
note: Run with `RUST_BACKTRACE=1` for a backtrace.

而且,我们这不还需要继续猜数字嘛。Err(_)是结果错误时返回要进行的操作,continue就能让它重新继续来猜。

cmp

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

使用cmp比较两个数,cmp结果会返回一个Ordering类型,我们可以事先定义这个三个可能的类型之后的操作。继续使用match {}来进行结果操作。会遍历定义的结果返回,如果匹配则执行。

如果只是一行代码的就不需要{}

至此,猜猜看就完成啦。

最近的文章

logstash-elasticsearch-kibana时间问题

基于elk搭建一套日志系统,在搭建的同时发现一个关于时间的问题。发现问题0x01设置索引mapping,写入日志,filebeat收集传送到logstash上。使用kibana查看数据,此时会发现,过去的十五分钟无数据。这是为啥?明明看到logstash写进去了。去看下文档数,确实写进去了。0x02十五分钟没有,往前半小时也是没有,一整天都没有(现在时间16点多)。将时间范围调整到整个月的时候,神奇的事发生了。。。在往后的八小时出现了数据了。这就是timezone的问题了。0x03使用...…

继续阅读
更早的文章

rust学习之一

第一次接触rust是因为在GitHub上面看到了一个好玩的项目,rust-sr这个能让图片更加清晰的工具。rust这个新兴的语言在人工智能方面运用的还是很有前景的。so,开始学习学习。教材我是用的教程是Rust 程序设计语言(第二版),刚加第一版的书签时,还没有呢。打算看的时候除了第二版,那就从第二版开始看.介绍 Rust 是一门着眼于安全、速度和并发的编程语言。其程序设计兼顾底层语言的性能与控制,并不失高级语言强大的抽象能力。其特性适合那些有类 C 语言经验,正在寻找更安全的替代品...…

继续阅读