Rust中文翻译6

时间:2021-05-01 14:52:10
3.1.3 生成秘密数
下面,我们需要生成一个秘密数字.Rust在标准库中没有包含生成随机数的功能.但是,Rust开发团队还是提供了一个rand crate.一个crate就是一个Rust语言的包.我们已经编译过一个二进制crate,也就是一个可执行程序.rand是一个库crate,它包含可以被其他程序使用的代码.
使用外部的crate正是Cargo闪耀的时刻.在我们编写使用rand的代码以前,我们需要修改我们的Cargo.toml文件.打开文件加入如下代码: [dependencies] rand="0.3.0"
Page 31
[dependencies]段和[package]段一样,任何其后的内容都是这个段的一部分,直到遇见了下一个段.Cargo使用这个段来知道你要使用哪些外部依赖的crate,以及它们的版本.在此例中,我们使用版本0.3.0.Cargo可以理解版本语法,这是一种书写版本号的标准语法.如果我们想使用最新版本,我们可以试用*号,或者使用一个版本区间.Cargo帮助文件中有详细的描述.
现在,不改变任何代码,我们来编译一下: Rust中文翻译6
(你可能会看到不同的数字) 这里有很多输出!现在我们有一个外部依赖,Cargo会取回注册在其中的所有项的最新版本,是对Cargo.io数据的拷贝.Cargo.io是Rust程序员发布他们的开源Rust工程的生态系统.
更新了注册表之后,Cargo检查依赖项然后下载那些我们还没有的东西.在此例中,尽管我们只声称要使用rand,但是我们还是获取到了libc这个依赖项.这是因为rand又是依赖于libc来工作的.下载完成以后,它会编译它并编译我们的工程.
如果我们再次运行cargo build,我们会得到不同的输出: Rust中文翻译6
这次没有任何输出!Cargo知道我们的工程已经编译好了,它所有的依赖项也都编译好了,所以没有必要再把那些内容输出一遍.所有的东西都已经存在了,所以它什么都不做.如果我们打开src/main.rs,随便做一些修改,保存并编译,我们会看到一行: Rust中文翻译6

Page 32
所以,我们告诉Cargo我们需要0.3.0版本的rand,它为我们升级到了0.3.8版本.但是如果下次升级到了0.3.9版本,而这一版本又有好多bug怎么办呢?
答案是如果你的工程目录下的Cargo.lock文件.当你第一次编译你的工程的时候,Cargo找到了所有你需要的依赖的版本,然后把它们写入Cargo.lock文件.当你下次再编译的时候,Cargo将会查看Cargo.lock文件是否存在,然后使用那些特定的版本,而不是再次查找所有新版本.这样我们就可以可重复性的自动编译.也就是说,我们可以停留在0.3.8版本直到我们需要显式的升级新版本,这一机制也适用于那些我们共享给到代码的人,多亏了这个lock文件.
如果我们确实想升级到0.3.9呢?Cargo还有另一个命令,update,也就是说"忽略那个lock文件,查找最新版本.如果存在,写入lock文件".但是默认的情况下,Cargo只会查找那些大于0.3.0小于.04.0的版本.如果我们要使用0.4.x,我们需要手动升级Cargo.toml文件.如果我们这样做,下次使用cargo build的时候,Cargo会更新并且重新编译我们的rand依赖项.
我们说了很多关于Cargo及其生态系统的事情,现在,这些对我们已经足够用了.Cargo使得使用库变得非常的容易,所以Rust程序员们喜欢写一些小程序但是包含很多库.
让我们继续看如何真正的使用rand.我们的下一步是: extern crate rand;
use std::io; 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); }
Page 33
我们做的第一件事就是修改了程序的第一行.那就是extern crate rand.因为我们在[dependencies]中声明了rand,我们可以使用extern crate来让Rust知道我们将要使用它.use rand这句话也做了同样的事情;所以我们可以通过一个前缀rand::来使用rand crate中的任何东西.
然后,我们添加了另一行:use rand::Rng.我们将要使用一个方法,需要将Rng在我们的作用域当中.基本的想法是:方法是一些被定义的"小功能(traits)",为了使它能工作,必须将他包含进我们的作用域当中.更多信息请阅读traits(5.20)一节.
代码的中间,我们添加了如下两行:      let secret_number = rand::thread_rng().gen_range(1, 101);
     println!("The secret number is: {}". secret_number); 我们使用了rand::thread_rng()方法来得到一个随机数生成器的拷贝, 就在我们的当前执行线程里.因为我们在之前写了ues rand::Rng,所以我们可以试用gen_range()方法.这个方法有两个参数,然后生成一个介于两者之间的随机数.左闭右开.所以写成(1, 101)才会得到1到100的一个随机数.
第二行只是打印这个数.当我们调试代码的时候很有用.但是我们会在最终版本删除这行代码.游戏开始的时候就告诉答案可不是一个什么好游戏!
试着运行我们的程序: Rust中文翻译6
很好!下一步:比较我们的猜测和秘密数.
Page 34
3.1.4 比较猜测 现在我们有了用户输入,让我们来比较一下随机数和我们的猜测吧.这是我们的下一步,虽然他并不能很好的工作: 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类型.