于是跟着「The Rust Programming Language」这本书,首先是一个很常见的语言入门的例子——猜数字。
这里一般会涉及随机数、标准输入输出、if 语句 / 函数匹配、字符串转整数、循环,然后作为入门的例子,也相对比较有趣233333
那这里顺着书的流程,首先是熟悉一下 print 这样的语句,然后接着是 new 对象,以及从标准输入读取数据~
use std::io; fn main() { println!("Guess Your Number!"); println!("Input your number:"); // new 一个 String 对象 guess // guess 是一个可变对象 let mut guess = String::new(); // 从标准输入中读取一行 // io::stdin().read_line() // // guess 作为可变对象传入 // 因为读取到的行的内容会放在 guess 里 // &mut guess // // io::stdin().read_line() 返回一个 io::Result // 要么是 Err, 要么是 Ok // - 当 io::Result 为 Err 时(即有错误发生时) // 程序会崩溃并显示传入 expect 中的字符串作为报错信息 // - 当 io::Result 为 Ok 时 // expect() 会返回上一个(这里即 read_line())的返回值 // read_line() 返回一共收到了多少个字节的数据 io::stdin().read_line(&mut guess) .expect("Failed to read line"); // 这里与 Python 类似 // 使用 {} 作为 placeholder // 后面传入变量的值会依次序替换 placeholder println!("You guessed: {}", guess); }
这些跟 C/C++/Swift 等等基本上差别不大~可以运行一下看看效果
然后就是怎么产生随机数了,这里「The Rust Programming Language」使用了 rand 这个包,于是在 Cargo.toml 中加入这个依赖~
加入完依赖之后则是实际调用
use std::io; use rand::Rng; fn main() { // 使用 rand 生成一个 [1, 101) 的数字 let secret_number = rand::thread_rng().gen_range(1, 101); // 并且输出它 println!("The secret number is: {}", secret_number); println!("Guess Your Number!"); println!("Input your number:"); let mut guess = String::new(); io::stdin().read_line(&mut guess) .expect("Failed to read line"); println!("You guessed: {}", guess); }
现在已经有了 secret number 和用户的输入了,就差比较是否相等了~
use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); println!("The secret number is: {}", secret_number); println!("Guess Your Number!"); println!("Input your number: "); let mut guess = String::new(); io::stdin().read_line(&mut guess) .expect("Failed to read line"); println!("You guessed: {}", guess); // 比较大小 // 两个值的比较结果有三种可能 // - std::cmp::Ordering::Less // - std::cmp::Ordering::Greater // - std::cmp::Ordering::Equal // // 接下来我们使用 match 表达式 // 紫色部分的结果会与下面列举的从上到下依次进行匹配 // 列举的部分在 Rust 中被称为 arm(红色部分) // 这里有三个 arm,对应于比较结果的三种可能 // 在 arm 中,左侧为 pattern // 即与紫色部分的结果进行匹配的东西 // 右侧则为匹配成功之后会运行的代码 match guess.cmp(&secret_number) { Ordering::Less => println!("Too small!"), Ordering::Greater => println!("Too big!"), Ordering::Equal => println!("You win!"), } }
当然,话是这么说,不过现在 guess 还是 String 类型的,需要转为 u32 类型的整数才可以与 secret_number 比较~否则的话,现在编译会因为 cmp 前后的变量类型不同报错。而 Rust 语言又是强静态类型的,所以 Rust 编译器检查到这里时就会报错( ;´Д`)
而我们在声明变量时可以不用显式注明变量类型则是因为 Rust 编译器根据上下文帮我们做了类型推理。这一点与 Swift 是一样的
其实将字符串尝试转为整数挺简单的,只需要加一两行即可~
use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); println!("The secret number is: {}", secret_number); println!("Guess Your Number!"); println!("Input your number: "); let mut guess = String::new(); io::stdin().read_line(&mut guess) .expect("Failed to read line"); // 尝试将从标准输入的 guess 转为 u32 类型的整数 // 如果转换失败 // 则说明用户输入的不是数字 // 提示 "Please type a number!" let guess: u32 = guess.trim().parse() .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!"), } }
现在编译的话就已经基本上没问题了(>^ω^<)
不过只能一次一次的运行,也就是说每次猜数字只有一次的机会(嘛,当然现在因为输出了 secret_number,所以要作弊的话一次也足够了233333)
那么要做成猜对了就退出的话,显然我们需要在 Greater / Less 的情况下继续,在 Equal 的时候可以退出循环,于是我们需要循环~
use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); println!("The secret number is: {}", secret_number); println!("Guess Your Number!"); // 无限循环 loop { println!("Input your number: "); let mut guess = String::new(); io::stdin().read_line(&mut guess) .expect("Failed to read line"); let guess: u32 = guess.trim().parse() .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!"); // 在 Equal 时退出循环 break; } } } }
现在编译的话,就是按我们的想法执行了(*/ω\*)
其实对于用户输入的 guess 来说的话,我们在 parse 的时候还可以再做得好一点,不要直接让程序崩溃报错,而是尝试跳到循环开始的地方,让用户重新输入(⁎⁍̴̛ᴗ⁍̴̛⁎) (顺便我们接下来也把输出 secret_number 的语句给删掉~)
use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); println!("Guess Your Number!"); loop { println!("Input your number: "); let mut guess = String::new(); io::stdin().read_line(&mut guess) .expect("Failed to read line"); let guess: u32 = match guess.trim().parse() { // 在可以正确转换为 u32 整数时返回转化的值 Ok(num) => num, // 在不能转换时 // 用 continue 回到循环开始处 // 让用户重新输入 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; } } } }
现在即使输入非数字,也可以不用像之前一样让程序崩溃了~ヽ(;▽;)ノ