我認爲學習計算機語言,應該先用後學,這一節,咱們來實現一個猜數字的小遊戲。
先簡單介紹一個這個遊戲的內容:遊戲先生成一個1到100之間的任意一個數字,而後咱們輸入本身猜想的數字,遊戲會告訴咱們輸入的數字太大仍是過小,而後咱們從新輸入新的數字,直到猜到遊戲生成的數字,而後遊戲結束。git
製做遊戲的第一步先建立項目,建立方法和上一節同樣,使用 cargo 來建立一個名爲 guessing_game 的項目。函數
cargo new guessing_game && cd guessing_game
項目建立完成,能夠運行一下,若是程序打印出 Hello, World! 則證實程序建立完成,運行命令以下:oop
cargo run
正式寫遊戲的第一步,讓遊戲先讀取咱們猜想的數字。咱們能夠先把打印語句換成提示咱們輸入數字的提示語句。學習
use std::io; fn main() { println!("猜想數字遊戲,請輸入您猜想的數字。"); let mut guess = String::new(); io::stdin().read_line(&mut guess).expect("讀取數字失敗!"); println!("您猜想的數字是:{}", guess); }
這段代碼包含了大量的信息,咱們一行一行地過一遍。
1.由於咱們須要讀取用戶的輸入,而後把它做爲結果打印出來,因此須要把 標準庫(被稱做 std )中的 io 依賴引入當前做用域。
2.在主函數中寫方法體,首先是打印提示語,不說了。
3.而後建立一個用於保存即將輸入的字符串的 String 類型的變量 guess。
4.把控制檯輸入的數字讀取到變量 guess 中,若是讀取失敗,則打印 「讀取數字失敗!」 的字符串。
5.把讀取的數字再打印到控制檯。測試
注:這段程序的細節暫時先不深究了,後續文章會一一解釋清楚。
測試一下這段程序:ui
cargo run Compiling guessing_game v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/guessing_game) Finished dev [unoptimized + debuginfo] target(s) in 1.01s Running `target/debug/guessing_game` 猜想數字遊戲,請輸入您猜想的數字。 2 您猜想的數字是:2
咱們的遊戲須要建立一個隨機數,供咱們去猜想,這個數字要求每次啓動遊戲時都是不相同的,這樣遊戲才更加有意思。接下來咱們在遊戲中生成一個1到100的隨機數。可是 rust 沒有在它的標準庫中提供生成隨機數的方法,不過不要緊,它提供了生成隨機數的名爲 rand 的 crate。咱們來引入一下生成隨機數的 crate,修改 Cargo.toml 文件:spa
[dependencies] rand = "^0.3.14"
只須要在 [dependencies] 下面添加須要的 crate 便可。此次添加的 crate 名字是 rand,版本號 0.3.14, 而 ^
的意思是兼容 0.3.14 版本的任何版本均可以。而後咱們編譯一下程序,就會自動下載引入的依賴:debug
cargo build Updating crates.io index Compiling libc v0.2.65 Compiling rand v0.4.6 Compiling rand v0.3.23 Compiling guessing_game v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/guessing_game) Finished dev [unoptimized + debuginfo] target(s) in 1m 13s
引入了生成隨機數和 crate 後,咱們來生成一下須要的 crate,代碼以下:code
use std::io; use rand::Rng; fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); println!("生成的隨機數字是:{}", secret_number); println!("猜想數字遊戲,請輸入您猜想的數字。"); let mut guess = String::new(); io::stdin().read_line(&mut guess).expect("讀取數字失敗!"); println!("您猜想的數字是:{}", guess); }
能夠看到咱們在前面代碼的基礎上添加了三行代碼:
1.第一行是引入生成隨機數的依賴。
2.第二行是生成一個隨機數,隨機數的範圍是 [1, 101),區間是左閉右開,說人話就是1到100。
3.第三行是打印生成的隨機數。
而後咱們測試一下添加的隨機數是否生效:遊戲
cargo run Compiling guessing_game v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/guessing_game) Finished dev [unoptimized + debuginfo] target(s) in 0.45s Running `target/debug/guessing_game` 生成的隨機數字是:79 猜想數字遊戲,請輸入您猜想的數字。 6 您猜想的數字是:6
如今咱們能夠輸入本身猜想的數字,也能夠生成隨機數字了,那麼接下來就是比較兩者的大小了。可是在比較以前還有個問題,控制檯輸入的數字是 string 類型的,而隨機生成的數字是無符號32位整型(u32),兩者不類型不一致,不能做比較,所以,在比較以前,咱們應該先把控制檯輸入的 string 類型的數字轉成u32類型的,代碼以下:
use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); println!("生成的隨機數字是:{}", secret_number); println!("猜想數字遊戲,請輸入您猜想的數字。"); let mut guess = String::new(); io::stdin().read_line(&mut guess).expect("讀取數字失敗!"); let guess: u32 = guess.trim().parse().expect("請輸入一個數字!"); println!("您猜想的數字是:{}", guess); match guess.cmp(&secret_number) { Ordering::Less => println!("您猜想的數字過小了!"), Ordering::Greater => println!("您猜想的數字太大了!"), Ordering::Equal => println!("恭喜您,猜對了!"), } }
可見,咱們在三個位置添加了代碼:
1.從標準庫中添加了比較的依賴。
2.把輸入的數字類型成u32類型,若是輸入的不是數字,則轉換失敗,打印出錯誤信息。
3.最後一部分就是比較一下兩者的大小,並打印出比較的結果。
好了,咱們先測試一下吧,這裏咱們只測正確的輸入:
cargo run 101 ↵ Compiling guessing_game v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/guessing_game) Finished dev [unoptimized + debuginfo] target(s) in 0.42s Running `target/debug/guessing_game` 生成的隨機數字是:53 猜想數字遊戲,請輸入您猜想的數字。 4 您猜想的數字是:4 您猜想的數字過小了!
咱們發現,咱們只輸入了一次,遊戲就結束了,這顯然不符合咱們的預期。咱們的預期是,咱們能夠一直猜一直猜,直到猜中才讓遊戲結束,那應該怎麼修改一下呢?添加一個循環,代碼以下:
use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); println!("生成的隨機數字是:{}", secret_number); loop { println!("猜想數字遊戲,請輸入您猜想的數字。"); let mut guess = String::new(); io::stdin().read_line(&mut guess).expect("讀取數字失敗!"); let guess: u32 = guess.trim().parse().expect("請輸入一個數字!"); println!("您猜想的數字是:{}", guess); match guess.cmp(&secret_number) { Ordering::Less => println!("您猜想的數字過小了!"), Ordering::Greater => println!("您猜想的數字太大了!"), Ordering::Equal => println!("恭喜您,猜對了!"), } } }
這裏修改得比較簡單,只須要添加一個名叫 loop 的關鍵字,而後把須要循環的內容放在 {} 中便可,而後咱們測試一下:
cargo run Compiling guessing_game v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/guessing_game) Finished dev [unoptimized + debuginfo] target(s) in 0.38s Running `target/debug/guessing_game` 生成的隨機數字是:71 猜想數字遊戲,請輸入您猜想的數字。 50 您猜想的數字是:50 您猜想的數字過小了! 猜想數字遊戲,請輸入您猜想的數字。 71 您猜想的數字是:71 恭喜您,猜對了! 猜想數字遊戲,請輸入您猜想的數字。 45 您猜想的數字是:45 您猜想的數字過小了! 猜想數字遊戲,請輸入 t thread 'main' panicked at '請輸入一個數字!: ParseIntError { kind: InvalidDigit }', src/libcore/result.rs:1165:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.
咱們的遊戲能夠屢次輸入了,可是有沒有發現一些問題呢?
1.遊戲直接告訴咱們生成的數字了,那就不用猜了,直接輸入就行了。
2.當咱們猜對後,遊戲沒有結束。
3.當咱們輸入的內容不是數字的時候,纔會結束遊戲,並且不只打印了咱們預期的錯誤信息,還打印了其它信息。
接下來,咱們把這些問題依次修改,代碼以下:
use std::io; use std::cmp::Ordering; use rand::Rng; fn main() { let secret_number = rand::thread_rng().gen_range(1, 101); // println!("生成的隨機數字是:{}", secret_number); loop { println!("猜想數字遊戲,請輸入您猜想的數字。"); let mut guess = String::new(); io::stdin().read_line(&mut guess).expect("讀取數字失敗!"); let guess: u32 = match guess.trim().parse() { Ok(num) => num, Err(_) => continue, }; println!("您猜想的數字是:{}", guess); match guess.cmp(&secret_number) { Ordering::Less => println!("您猜想的數字過小了!"), Ordering::Greater => println!("您猜想的數字太大了!"), Ordering::Equal => { println!("恭喜您,猜對了!"); break; } } } }
這三處錯誤的修改方式依次是:
1.把打印隨機數的代碼註釋掉。
2.在作類型轉換時,使用 match 關鍵字做判斷,若是轉化成功,則返回轉化後的結果,若是轉化失敗,無論由於什麼緣由失敗,都直接跳出本次循環。
3.在作二個數字大小判斷時,若是判斷相等,則結束循環。
咱們來測試一下修改的結果:
cargo run Compiling guessing_game v0.1.0 (/Users/shanpengfei/work/rust-work-space/study/guessing_game) Finished dev [unoptimized + debuginfo] target(s) in 0.38s Running `target/debug/guessing_game` 猜想數字遊戲,請輸入您猜想的數字。 50 您猜想的數字是:50 您猜想的數字過小了! 猜想數字遊戲,請輸入您猜想的數字。 r 猜想數字遊戲,請輸入您猜想的數字。 75 您猜想的數字是:75 您猜想的數字過小了! 猜想數字遊戲,請輸入您猜想的數字。 87 您猜想的數字是:87 您猜想的數字太大了! 猜想數字遊戲,請輸入您猜想的數字。 81 您猜想的數字是:81 恭喜您,猜對了!
能夠看到咱們的遊戲製做完成了~~
歡迎閱讀單鵬飛的學習筆記