Rust猜数字之比较

比较

     既然我们获得了用户的输入,让我们把猜测的数据跟神秘数字做比较。这是我们的下一步,尽管它还不能真正工作:

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

         println!("The secret number is: {}", secret_number);

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

         let mut guess = String::new();

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

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

         match guess.cmp(&secret_number) {
             Ordering::Less    => println!("Too small!"),
             Ordering::Greater => println!("Too big!"),
             Ordering::Equal   => println!("You win!"),
         }
     }
   
     一些新加入的内容。第一个是另外一个use。我们带来了一个新类型叫做std::cmp::Ordering。底部有5行使用它:

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

     cmp()方法可以在任何可比较的东西上调用,它会使用你要比较的东西的一个引用。它将会返回我们前面使用的Ordering类型。我们使用match声明来决定确切的是那种Ordering。Ordering是一个枚举(enum),‘enumeration’的缩写,看起来是这样子的:

     enum Foo{
          Bar,
          Baz,
     }

     有了这个定义,所有是Foo类型的不是Foo::Bar就是Foo::Baz。我们使用::来指明特定枚举变量的命名空间。

     Ordering枚举类型有三种可能的变化:Less、Equal和Greater。match声明使用一种类型的值,并为每种可能的值创建一个分支‘arm’。因为我们有三种类型的Ordering,我们有三种分支(arms):
     match guess.cmp(&secret_number) {
             Ordering::Less    => println!("Too small!"),
             Ordering::Greater => println!("Too big!"),
             Ordering::Equal   => println!("You win!"),
     }

     如果是Less,我们打印Too small!,如果是Greater,打印Too big!,如果是Equal,打印You win!。match很有用,在Rust中经常用到。

     我提到过这个程序不能工作。让我们试一下:

     $ cargo build
        Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game)
     src/main.rs:28:21: 28:35 error: mismatched types:
     expected `&collections::string::String`,
         found `&_`
     (expected struct `collections::string::String`,
         found integral variable) [E0308]
     src/main.rs:28     match guess.cmp(&secret_number) {
                                        ^~~~~~~~~~~~~~
     error: aborting due to previous error
     Could not compile `guessing_game`.

     这是一个严重的错误。主要的愿意是我们有‘不匹配的类型’。Rust有一个强、静态类型系统。然而,它有类型推断功能。当我们写let guess = String::new()时,Rust能够推断出guess是一个String类型,所以它没有要求我们写出类型。对于我们的secret_number,有一些类型可以有1-100之间的值:i32,一个32位的数,或者u32,一个无符号32位数,或i64,一个64位数。或者其它的。迄今为止,这都不是问题,Rust默认是一个i32.然而,在这里,Rust不知道怎么比较guess和secret_number。他们需要是相同的类型。最终,我们想将我们读取到的String转换成一个真正的数字类型。我们可以通过额外的三行代码实现。这是我们的新程序:

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

         println!("The secret number is: {}", secret_number);

         println!("Please input your guess.");
     
         let mut guess = String::new();

         io::stdin().read_line(&mut guess)
             .ok()
             .expect("failed to read line");
     
         let guess: u32 = guess.trim().parse()
             .ok()
             .expect("Please type a number!");

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

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

     新的3行是:

      let guess: u32 = guess.trim().parse()
             .ok()
             .expect("Please type a number!");

     等一下,我们不是已经有一个guess了吗?我们确实有了,但是Rust允许我们使用一个新的隐藏(shadow)先前的。在这种情况下经常使用,当guess以String开始,但是我们想将其转换成一个u32类型的数据。隐藏技术允许我们重用guees名字,而不是强制我们想出两个不一样的名字,例如guess_str和guess,或者其它的。

     我们将guess绑定到一个与我们先前看起来有些相像的表达式上:

     guess.trim().parse()

     跟随着一个ok().expect()调用。这里guess指的是老guess,也就是保存我们输入的那个String。String上的trim()方法将会消除字符串开头和结尾的所有空白字符。这个很重要,因为我们要满足read_line()必须按下回车键(return)。这意味着如果我们输入5并敲击回车键,guess看起来将会这样:5\n。\n代表换行(newline),输入(enter)键。trim()去掉它,留下我们的字符串仅仅包含5。字符串上的的parse()方法将字符串解析成某种类型的数字。因为它可以解析多种数字,我们需要给Rust一个暗示,来获取我们想要的数字的类型。因此,let guess: u32。guess后面的冒号(:)告诉Rust我们将阐明它的类型。u32是一个无符号、32位整数。Rust有一些内建数字类型,但是我们已经选择u32.对于一个小正整数这是一个很好的默认选择。

     跟read_line()一样。我们的对parse()的调用会产生一个错误。如果我们的字符串包含 A% 将会怎样?将没有方法将其转换成数字。同样,我们将会跟read_line()一样做同样的事情:如果有错误发生,使用ok()和expect()方法使程序崩溃。

     让我们试一下程序!

     $ cargo run
        Compiling guessing_game v0.0.1 (file:///home/you/projects/guessing_game)
          Running `target/guessing_game`
     Guess the number!
     The secret number is: 58
     Please input your guess.
       76
     You guessed: 76
     Too big!

     非常好!你可以看到我输入的空格,但是他依旧会指出我猜的是76。多运行几次程序,验证猜数字程序正常工作。

     现在我们可以是程序的大部分工作,但是我们只能裁一次。让我们使用循环改改它!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值