<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 猜猜看 > [guessing-game.md](https://github.com/rust-lang/rust/blob/master/src/doc/book/guessing-game.md) commit 6ba952020fbc91bad64be1ea0650bfba52e6aab4 讓我學習一些 Rust!作為第一個項目,我們來實現一個經典新手編程問題:猜猜看游戲。它是這么工作的:程序將會隨機生成一個 1 到 100 之間的隨機數。它接著會提示猜一個數。當我們猜了一個數之后,它會告訴我們是太大了還是太小了。猜對了,它會祝賀我們。聽起來如何? ### 準備 讓我們準備一個新項目。進入到項目目錄。還記得之前如何創建`hello_world`的項目目錄和`Cargo.toml`文件的嗎?Cargo 有一個命令來做這些。讓我們試試: ~~~ $ cd ~/projects $ cargo new guessing_game --bin $ cd guessing_game ~~~ 我們將項目名字傳遞給`cargo new`,然后用了`--bin`標記,因為要創建一個二進制文件,而不是一個庫文件。 查看生成的`Cargo.toml`文件: ~~~ [package] name = "guessing_game" version = "0.1.0" authors = ["Your Name <you@example.com>"] ~~~ Cargo 從系統環境變量中獲取這些信息。如果這不對,趕緊修改它。 最后,Cargo 為我們生成了一個“Hello, world!”。查看`src/main.rs`文件: ~~~ fn main() { println!("Hello, world!"); } ~~~ 讓我們編譯 Cargo 為我們生成的項目: ~~~ $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) ~~~ 很好!再次打開你的`src/main.rs`文件。我們會將所有代碼寫在這個文件里。稍后我們會講到多文件項目。 在我們繼續之前,讓我們再告訴你一個新的 Cargo 命令:`run`。`cargo run`跟`cargo build`類似,并且還會運行我們剛生成的可執行文件。試試它: ~~~ $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) Running `target/debug/guessing_game` Hello, world! ~~~ 很好!`run`命令在我們需要快速重復運行一個項目時非常方便。我們的游戲就是這么一個項目,在我們添加新內容之前我們需要經常快速測試項目。 ### 處理一次猜測 讓我們開始吧!我們需要做的第一件事是讓我們的玩家輸入一個猜測。把這些放入你的`src/main.rs`: ~~~ use std::io; fn main() { println!("Guess the number!"); println!("Please input your guess."); let mut guess = String::new(); io::stdin().read_line(&mut guess) .expect("Failed to read line"); println!("You guessed: {}", guess); } ~~~ 這有好多東西!讓我們一點一點地過一遍。 ~~~ use std::io; ~~~ 我們需要獲取用戶輸入,并接著打印結果作為輸出。為此,我們需要標準庫的`io`庫。Rust 為所有程序只導入了很少一些東西,[‘prelude’](http://doc.rust-lang.org/nightly/std/prelude/)。如果它不在預先導入中,你將不得不直接`use`它。這還有第二個"prelude",[`io`prelude](http://doc.rust-lang.org/std/io/prelude/index.html),它也起到了類似的作用:你引入它,它引入一系列擁有的 IO 相關的庫。 ~~~ fn main() { ~~~ 就像你之前見過的,`main()`是你程序的入口點。`fn`語法聲明了一個新函數,`()`表明這里沒有參數,而`{`開始了函數體。因為不包含返回類型,它假設是`()`,一個空的[元組](#)。 ~~~ println!("Guess the number!"); println!("Please input your guess."); ~~~ 我們之前學過`println!()`是一個在屏幕上打印[字符串](#)的[宏](#)。 ~~~ let mut guess = String::new(); ~~~ 現在我們遇到有意思的東西了!這一小行有很多內容。第一個我們需要注意到的是[let語句](#),它用來創建“變量綁定”。它使用這個形式: ~~~ let foo = bar; ~~~ 這會創建一個叫做`foo`的新綁定,并綁定它到`bar`這個值上。在很多語言中,這叫做一個“變量",不過 Rust 的變量綁定暗藏玄機。 例如,它們默認是[不可變的](#)。這時為什么我們的例子使用了`mut`:它讓一個綁定可變,而不是不可變。`let`并不從左手邊獲取一個名字,事實上它接受一個[模式(pattern)](#)。我們會在后面更多的使用模式。現在它使用起來非常簡單: ~~~ let foo = 5; // immutable. let mut bar = 5; // mutable ~~~ 噢,同時`//`會開始一個注釋,直到這行的末尾。Rust 忽略[注釋](#)中的任何內容。 那么現在我們知道了`let mut guess`會引入一個叫做`guess`的可變綁定,不過我們也必須看看`=`的右側所綁定的內容:`String::new()`。 `String`是一個字符串類型,由標準庫提供。[String](#)是一個可增長的,UTF-8編碼的文本。 `::new()`語法用了`::`因為它是一個特定類型的”關聯函數“。這就是說,它與`String`自身關聯,而不是與一個特定的`String`實例關聯。一些語言管這叫一個“靜態方法”。 這個函數叫做`new()`,因為它創建了一個新的,空的`String`。你會在很多類型上找到`new()`函數,因為它是創建一些類型新值的通常名稱。 讓我們繼續: ~~~ io::stdin().read_line(&mut guess) .expect("Failed to read line"); ~~~ 這稍微有點多!讓我們一點一點來。第一行有兩部分。這是第一部分: ~~~ io::stdin() ~~~ 還記得我們如何在程序的第一行`use std::io`的嗎?現在我們調用了一個與之相關的函數。如果我們不`use std::io`,那么我們就得寫成`std::io::stdin()`。 這個特殊的函數返回一個指向你終端標準輸入的句柄。更具體的,可參考[std::io::Stdin](http://doc.rust-lang.org/stable/std/io/struct.Stdin.html)。 下一部分將用這個句柄去獲取用戶輸入: ~~~ .read_line(&mut guess) ~~~ 這里,我們對我們的句柄調用了[read_line()](http://doc.rust-lang.org/stable/std/io/struct.Stdin.html#method.read_line)方法。[“方法”](#)就像關聯函數,不過只在一個類型的特定實例上可用,而不是這個類型本身。我們也向`read_line()`傳遞了一個參數:`&mut guess`。 還記得我們上面怎么綁定`guess`的嗎?我們說它是可變的。然而,`read_line`并不接收`String`作為一個參數:它接收一個`&mut String`。Rust有一個叫做[“引用”](#)的功能,它允許你對一片數據有多個引用,用它可以減少拷貝。引用是一個復雜的功能,因為Rust的一個主要賣點就是它如何安全和便捷地使用引用。然而,目前我們還不需要知道很多細節來完成我們的程序。現在,所有我們需要了解的是像`let`綁定,引用默認是不可變的。因此,我們需要寫成`&mut guess`,而不是`&guess`。 為什么`read_line()`會需要一個字符串的可變引用呢?它的工作是從標準輸入獲取用戶輸入,并把它放入一個字符串。所以它用字符串作為參數,為了可以增加輸入,它必須是可變的。 不過我們還未完全看完這行代碼。雖然它是單獨的一行代碼,但只是這個單獨邏輯代碼行的開頭部分: ~~~ .expect("Failed to read line"); ~~~ 當你用`.foo()`語法調用一個函數的時候,你可能會引入一個新行符或其它空白。這幫助我們拆分長的行。我們*可以*這么干: ~~~ io::stdin().read_line(&mut guess).expect("failed to read line"); ~~~ 不過這樣會難以閱讀。所以我們把它分開,3 行對應 3 個方法調用。我們已經談論過了`read_line()`,不過`expect()`呢?好吧,我們已經提到過`read_line()`將用戶輸入放入我們傳遞給它的`&mut String`中。不過它也返回一個值:在這個例子中,一個[io::Result](http://doc.rust-lang.org/stable/std/io/type.Result.html)。Rust的標準庫中有很多叫做`Result`的類型:一個泛型[Result](http://doc.rust-lang.org/stable/std/result/enum.Result.html),然后是子庫的特殊版本,例如`io::Result`。 這個`Result`類型的作用是編碼錯誤處理信息。`Result`類型的值,像任何(其它)類型,有定義在其上的方法。在這個例子中,`io::Result`有一個[expect()方法](http://doc.rust-lang.org/stable/std/option/enum.Option.html#method.expect)獲取調用它的值,而且如果它不是一個成功的值,[panic!](#)并帶有你傳遞給它的信息。這樣的`panic!`會使我們的程序崩潰,顯示(我們傳遞的)信息。 如果我們去掉這兩個函數調用,我們的程序會編譯通過,不過我們會得到一個警告: ~~~ $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) src/main.rs:10:5: 10:39 warning: unused result which must be used, #[warn(unused_must_use)] on by default src/main.rs:10 io::stdin().read_line(&mut guess); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~ Rust警告我們我們并未使用`Result`的值。這個警告來自`io::Result`的一個特殊注解。Rust 嘗試告訴你你并未處理一個可能的錯誤。阻止錯誤的正確方法是老實編寫錯誤處理。幸運的是,如果我們只是想如果這有一個問題就崩潰的話,我們可以用這兩個小方法。如果我們想從錯誤中恢復什么的,我們得做點別的,不過我們會把它留給接下來的項目。 這是我們第一個例子僅剩的一行: ~~~ println!("You guessed: {}", guess); } ~~~ 這打印出我們保存輸入的字符串。`{}`是一個占位符,所以我們傳遞`guess`作為一個參數。如果我們有多個`{}`,我們應該傳遞多個參數: ~~~ let x = 5; let y = 10; println!("x and y: {} and {}", x, y); ~~~ 簡單加愉快。 總而言之,這只是一個觀光。我們可以用`cargo run`運行我們寫的: ~~~ $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) Running `target/debug/guessing_game` Guess the number! Please input your guess. 6 You guessed: 6 ~~~ 好的!我們的第一部分完成了:我們可以從鍵盤獲取輸入,并把它打印回去。 ### 生成一個秘密數字 接下來,我們要生成一個秘密數字。Rust標準庫中還未包含隨機數功能。然而,Rust 團隊確實提供了一個[`rand` crate](https://crates.io/crates/rand)。一個“包裝箱”(crate)是一個 Rust 代碼的包。我們已經構建了一個”二進制包裝箱“,它是一個可執行文件。`rand`是一個”庫包裝箱“,它包含被認為應該被其它程序使用的代碼。 使用外部包裝箱是 Cargo 的亮點。在我們使用`rand`編寫代碼之前,我們需要修改我們的`Cargo.toml`。打開它,并在末尾增加這幾行: ~~~ [dependencies] rand="0.3.0" ~~~ `Cargo.toml`的`[dependencies]`部分就像`[package]`部分:所有之后的東西都是它的一部分,直到下一個部分開始。Cargo使用依賴部分來知曉你用的外部包裝箱的依賴,和你要求的版本。在這個例子中,我們用了`0.3.0`版本。Cargo理解[語義化版本](http://semver.org/lang/zh-CN/),它是一個編寫版本號的標準。如果我們就是只想使用`0.3.0`,我們可以用`=0.3.0`。如果我們想要使用最新版本我們可以使用`*`或者我們可以使用一個范圍的版本。[Cargo文檔](http://doc.crates.io/crates-io.html)包含更多細節。 現在,在不修改任何我們代碼的情況下,讓我們構建我們的項目: ~~~ $ cargo build Updating registry `https://github.com/rust-lang/crates.io-index` Downloading rand v0.3.8 Downloading libc v0.1.6 Compiling libc v0.1.6 Compiling rand v0.3.8 Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) ~~~ (當然,你可能會看到不同的版本) 很多新的輸出!現在我們有了一個外部依賴,Cargo 從記錄中獲取了所有東西的最新版本,它們是來自[Crates.io](https://crates.io/)的一份拷貝。Crates.io 是 Rust 生態系統中人們發表開源 Rust 項目供他人使用的地方。 在更新了記錄后,Cargo 檢查我們的`[dependencies]`并下載任何我們還沒有的東西。在這個例子中,雖然我們只說了我們要依賴`rand`,我們也獲取了一份`libc`的拷貝。這是因為`rand`依賴`libc`工作。在下載了它們之后,它編譯它們,然后接著編譯我們的項目。 如果我們再次運行`cargo build`,我們會得到不同的輸出: ~~~ $ cargo build ~~~ 沒錯,沒有輸出!Cargo 知道我們的項目被構建了,并且所有它的依賴也被構建了,所以沒有理由再做一遍所有這些。沒有事情做,它簡單地退出了。如果我們再打開`src/main.rs`,做一個無所謂的修改,然后接著再保存,我們就會看到一行: ~~~ $ cargo build Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) ~~~ 所以,我們告訴Cargo我們需要任何`0.3.x`版本的`rand`,并且因此它獲取在本文被編寫時的最新版,`v0.3.8`。不過你瞧瞧當下一周,`v0.3.9`出來了,帶有一個重要的 bug 修改嗎?雖然 bug 修改很重要,不過如果`0.3.9`版本包含破壞我們代碼的回歸呢? 這個問題的回答是現在你會在你項目目錄中找到的`Cargo.lock`。當你第一次構建你的項目的時候,Cargo 查明所有符合你的要求的版本,并接著把它們寫到了`Cargo.lock`文件里。當你在未來構建你的項目的時候,Cargo 會注意到`Cargo.lock`的存在,并接著使用指定的版本而不是再次去做查明版本的所有工作。這讓你有了一個可重復的自動構建。換句話說,我們會保持在`0.3.8`直到我們顯式的升級,這對任何使用我們共享的代碼的人同樣有效,感謝鎖文件。 當我們*確實*想要使用`v0.3.9`怎么辦?Cargo 有另一個命令,`update`,它代表“忽略鎖,搞清楚所有我們指定的最新版本。如果這能工作,將這些版本寫入鎖文件”。不過,默認,Cargo 只會尋找大于`0.3.0`小于`0.4.0`的版本。如果你想要移動到`0.4.x`,我們不得不直接更新`Cargo.toml`文件。當我們這么做,下一次我們`cargo build`,Cargo會更新索引并重新計算我們的`rand`要求。 關于[Cargo](http://doc.crates.io/)和[它的生態系統](http://doc.crates.io/crates-io.html)有很多東西要說,不過眼下,這是我們需要知道的一切。Cargo讓重用庫變得真正的簡單,并且Rustacean們可以編寫更小的由很多子包組裝成的項目。 讓我們真正的*使用*`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) .expect("failed to read line"); println!("You guessed: {}", guess); } ~~~ 先修改第一行。現在它是`extern crate rand`。因為在`[dependencies]`聲明了`rand`,我們可以用`extern crate`來讓Rust知道我們正在使用它。這也等同于一個`use rand;`,所以我們可以通過`rand::`前綴使用`rand`包裝箱中的一切。 下一步,我們增加了另一行`use`:`use rand::Rng`。我們一會將要使用一個方法,并且它要求`Rng`在作用域中才能工作。這個基本觀點是:方法定義在一些叫做“特性(traits,也有譯作特質)”的東西上面,而為了讓方法能夠工作,需要這個特性位于作用域中。關于更多細節,閱讀[trait](#)部分。 這里還有兩行我們增加的,在中間: ~~~ let secret_number = rand::thread_rng().gen_range(1, 101); println!("The secret number is: {}", secret_number); ~~~ 我們用`rand::thread_rng()`函數來獲取一個隨機數生成器的拷貝,它位于我們特定的執行[線程](#)的本地。因為`use rand::Rng`了,有一個`gen_range()`方法可用。這個函數獲取兩個參數,并產生一個位于其間的數字。它包含下限,不過不包含上限,所以需要`1`和`101`來生成一個`1`和`100`之間的數。 第二行僅僅打印出了秘密數字,這在開發程序時做簡單測試很有用。不過在最終版本中我們會刪除它。在開始就打印出結果就沒什么可玩的了! 嘗試運行新程序幾次: ~~~ $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) Running `target/debug/guessing_game` Guess the number! The secret number is: 7 Please input your guess. 4 You guessed: 4 $ cargo run Running `target/debug/guessing_game` Guess the number! The secret number is: 83 Please input your guess. 5 You guessed: 5 ~~~ 好的!接下來:讓我們比較我們的猜測和秘密數字。 ### 比較猜測 現在我們得到了用戶輸入,讓我們比較我們的猜測和隨機值。這是我們的下一步,雖然它還不能正常工作: ~~~ 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) .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()`可以在任何能被比較的值上調用,并且它獲取你想要比較的值的引用。它返回我們之前`use`的`Ordering`類型。我們使用一個[match](#)語句來決定具體是哪種`Ordering`。`Ordering`是一個[枚舉(enum)](#),它看起來像這樣: ~~~ enum Foo { Bar, Baz, } ~~~ 通過這個定義,任何`Foo`可以是`Foo::Bar`或者`Foo::Baz`。我們用`::`來表明一個特定`enum`變量的命名空間。 [Ordering](http://doc.rust-lang.org/stable/std/cmp/enum.Ordering.html)枚舉有3個可能的變量:`Less`,`Equal`和`Greater`。`match`語句獲取類型的值,并讓你為每個可能的值創建一個“分支”。因為有 3 種類型的`Ordering`,我們有 3 個分支: ~~~ 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`轉換為一個真正的數字類型,來進行比較。我們可以用額外 3 行來搞定它。這是我們的新程序: ~~~ 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) .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!"), } } ~~~ 新的 3 行是: ~~~ let guess: u32 = guess.trim().parse() .expect("Please type a number!"); ~~~ 稍等,我認為我們已經用過了一個`guess`?確實,不過 Rust 允許我們用新值“遮蓋(shadow)”之前的`guess`。這在這種具體的情況中經常被用到,`guess`開始是一個`String`,不過我們想要把它轉換為一個`u32`。遮蓋(Shadowing)讓我們重用`guess`名字,而不是強迫我們想出兩個獨特的像`guess_str`和`guess`,或者別的什么。 我們綁定`guess`到一個看起來像我們之前寫的表達式: ~~~ guess.trim().parse() ~~~ 這里,`guess`引用舊的`guess`,那個我們輸入用到的`String`。`String`的`trim()`方法會去掉我們字符串開頭和結尾的任何空格。這很重要,因為我們不得不按“回車”鍵來滿足`read_line()`。這意味著如果輸入`5`并按回車,`guess`看起來像這樣:`5\n`。`\n`代表“新行”,回車鍵。`trim()`去掉這些,保留`5`給我們的字符串。[字符串的`parse()`方法](http://doc.rust-lang.org/stable/std/primitive.str.html#method.parse)將字符串解析為一些類型的數字。因為它可以解析多種數字,我們需要給Rust一些提醒作為我們具體想要的數字的類型。因此,`let guess: u32`。`guess`后面的分號(`:`)告訴 Rust 我們要標注它的類型。`u32`是一個無符號的,32位整型。Rust 有[一系列內建數字類型](#),不過我們選擇了`u32`。它是一個小正數的默認好選擇。 就像`read_line()`,我們調用`parse()`可能產生一個錯誤。如果我們的字符串包含`A?%?`呢?并不能將它們轉換成一個數字。為此,我們將做我們在`read_line()`時做的相同的事:使用`expect()`方法來在這里出現錯誤時崩潰。 讓我們嘗試下我們的程序! ~~~ $ cargo run Compiling guessing_game v0.1.0 (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。運行這個程序幾次,并檢測猜測正確的值,和小的值。 現在我們讓游戲大體上能玩了,不過我們只能猜一次。讓我們增加循環來改變它! ### 循環 `loop`關鍵字給我們一個無限循環。讓我們加上它: ~~~ 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); 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 = 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!"), } } } ~~~ 并試試看。不過稍等,難道我們僅僅加上一個無限循環嗎?是的。記得我們我們關于`parse()`的討論嗎?如果我們給出一個非數字回答,明顯我們會`return`并退出: ~~~ $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) Running `target/guessing_game` Guess the number! The secret number is: 59 Please input your guess. 45 You guessed: 45 Too small! Please input your guess. 60 You guessed: 60 Too big! Please input your guess. 59 You guessed: 59 You win! Please input your guess. quit thread '<main>' panicked at 'Please type a number!' ~~~ 啊哈!`quit`確實退出了。就像任何其它非數字輸入。好吧,這至少不是最差的想法。首先,如果你贏得了游戲,那我們就真的退出它: ~~~ 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); 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 = 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!"); break; } } } } ~~~ 通過在`You win!`后增加`break`,我們將在你贏了后退出循環。退出循環也意味著退出程序,因為它是`main()`中最后的東西。我們僅僅需要再做一個小修改:當誰輸入了一個非數字,我們并不想退出,我們就想忽略它。我們可以這么做: ~~~ 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); 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; } } } } ~~~ 這是改變了的行: ~~~ let guess: u32 = match guess.trim().parse() { Ok(num) => num, Err(_) => continue, }; ~~~ 這是你如何大體上從“錯誤就崩潰”移動到“確實處理錯誤”,通過從`ok().expect()`切換到一個`match`語句。`parse()`返回的`Result`就是一個像`Ordering`一樣的枚舉,不過在這個例子中,每個變量有一些數據與之相關:`Ok`是一個成功,而`Err`是一個失敗。每一個都包含更多信息:成功的解析為整型,或一個錯誤類型。在這個例子中,我們`match`為`Ok(num)`,它設置了`Ok`內叫做`num`的值,接著在右側返回它。在`Err`的情況下,我們并不關心它是什么類型的錯誤,所以我們僅僅使用`_`而不是一個名字。這忽略錯誤,并`continue`造成我們進行`loop`的下一次迭代。 現在應該搞定了!試試看: ~~~ $ cargo run Compiling guessing_game v0.1.0 (file:///home/you/projects/guessing_game) Running `target/guessing_game` Guess the number! The secret number is: 61 Please input your guess. 10 You guessed: 10 Too small! Please input your guess. 99 You guessed: 99 Too big! Please input your guess. foo Please input your guess. 61 You guessed: 61 You win! ~~~ 狂拽炫酷!通過一個最后的修改,我們就完成了猜猜看游戲。你能想到它是什么嗎?對了,我們并不想打印出秘密數字。它有利于測試,不過有點毀游(san)戲(guan)的味道。這是最終源碼: ~~~ 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; } } } } ~~~ ### 完成! 此刻,你成功地構建了猜猜看游戲!恭喜! 這第一個項目展示了:`let`、`match`、方法、關聯函數、使用外部包裝箱等。下一個項目將會向你展示更多。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看