您好,登錄后才能下訂單哦!
這篇文章主要講解了“Rust學習筆記之實現一個猜謎游戲小項目的方法教程”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Rust學習筆記之實現一個猜謎游戲小項目的方法教程”吧!
并不是所有的代碼都像hello_world.rs
一樣,一個文件就可以搞定。一個項目往往具有復雜的代碼,我們需要一種機制來管理這種復雜性,將一個項目切分成若干小部分,每個部分再進行切分,層層抽象,直到達到人腦可以處理的規模。每種編程語言都有這樣的機制,例如Java的package機制,Rust也不例外。
Rust用了兩個概念來管理項目:一個是crate(項目),一個是mod(模塊)。模塊是用于在crate內部進行分層和封裝的機制,模塊內部可以包含模塊。
crate:可以簡單理解為一個項目,crate是Rust中的獨立編譯單元(compile unit),每個crate對應生成一個庫或者可執行文件。作為對比,我們比較熟悉的C語言中,一個單獨的.c文件和其所有的include文件組成一個編譯單元,每個.c生成一個.o,然后將這些.o鏈接起來生成可執行文件。
mod:可以簡單理解為命名空間。mod可以嵌套(注意crate之間不能出現循環引用),還可以控制內部元素的可見性。
說到可見性問題,在Rust中,元素默認都是私有的,用pub
關鍵字修飾的才是公開的。公開和私有的訪問權限規定如下:
如果一個元素是私有的,那么只有本模塊內的元素以及它的子模塊可以訪問
如果一個元素是公開的,那么可以在本模塊外的作用域訪問它。
模塊是一種抽象的概念,文件是承載這個概念的實體,但是模塊和文件并不是簡單的一一對應關系。在一個crate內部創建mod的方式有下面三種:
在一個rs文件中創建內嵌模塊,直接使用mod
關鍵字即可。
獨立的一個rs文件就是一個模塊,文件名即是模塊名。
一個文件夾也可以創建一個模塊,文件夾內部要有一個xxx.rs
文件,這個文件是這個模塊的入口。必須要在這個xxx.rs
中聲明其子模塊,否則子模塊無法被當成這個項目的源碼進行編譯。
cargo不僅是Rust的包管理器,還可以用于創建項目。使用下列命令可以創建一個名為guessing_game
的項目:
cargo new guessing_game --bin
注意,后面的--bin
意味著我們希望項目生成的是可執行程序,如果希望是library,則可以使用--lib
選項。
以上為在命令行中手工創建項目,在Clion中可以點擊File->New Project
后如下圖填寫,然后點擊Create
按鈕:
我們可以使用tree .
命令或者直接在Clion中查看當前的文件夾結構,如下圖所示:
src/main.rs:這是cargo自動生成的rs文件。還記得前面講的crate和mod的概念嗎?在這個項目中,guessing_game
是crate,src
文件夾是mod,main.rs
是src
mod的入口。我們可以在src
mod中創建子模塊,但注意,這些子模塊都要在main.rs
中聲明,否則無法參與編譯。
.gitignore:這是git忽略文件,不懂其作用的同學可以自行搜索。這里重點要說的是通過cargo new
創建的項目天然就是一個git項目,這也印證了Rust對開源的擁護。
Cargo.toml:這是項目管理配置文件。TOML是一種非常簡潔好用的配置文件格式,TOML是Tom's Obvious, Minimal Language
的首字母縮寫,這里的Tom是Github的聯合創始人之一,感興趣的同學可以進一步自行了解TOML配置文件的寫法。
Cargo.lock:該文件包含項目依賴項的確切信息,由Cargo維護,我們無須關心它。
在src/main.rs
里cargo已經自動生成了輸出Hello, world!
的代碼,我們來運行一下它看能否正常輸出。
插一句題外話,在你日后漫長的Rust編碼生涯中,你會發現,你將在處理編譯錯誤上耗費大量的時間。還記得嗎,Rust 的一大特色是保證內存安全,這保證了Rust代碼只要運行起來就幾乎不會發生內存錯誤,這么誘人的效果的背后的代價就是,我們要在編碼時付出額外的努力。Rust為了保證內存安全設計了一套復雜的規則,這導致我們的代碼一不留神就會編譯不過。所以,在你日后經常用的一個操作就是檢查能否編譯通過,而不是直接編譯,因為直接編譯還要做代碼優化等會相對費時。可以使用下列命令檢查編譯錯誤:
cargo check
在Clion中需要新加一個Configuration來執行cargo check
命令,如下圖所示:
確保cargo check
通過后,可以執行cargo build
來執行編譯。編譯后會產生一個target
文件夾,在target/debug
下會有一個和crate同名的可執行文件。但一般為了方便,可以直接執行cargo run
,這條命令等價于先編譯后執行。下圖是執行cargo run
后Clion的控制臺輸出:
在完成了項目搭建后,接下來就要開始猜謎游戲的代碼編寫了,我將它們分成六部分:創建變量、輸入、輸出、錯誤處理、隨機數生成、完整代碼。
使用let
語句創建變量,需要注意的是,在Rust中,變量默認是不可變的,可以在變量名前使用mut
來使得變量可變:
let a = 5; // 不可變 let mut b = 10; // 可變
在上面的let
語句中,我們并沒有顯示聲明變量的類型,但這并不代表Rust是動態類型的,Rust仍然是靜態類型的,只不過Rust有一個可以通過上下文推斷類型的強大編譯器。
我們早已在hello_world.rs
中見識過了最基本的輸出方式:
println!("Hello, world!");
需要注意的是,這里的println!
是一個宏,而非一個函數,println后面的感嘆號就是宏的標志。Rust中的宏與C/C++中的宏是完全不一樣的東西,簡單說,可以把它理解為一種安全版的編譯期語法擴展。這里之所以使用輸出宏而非函數,是因為標準輸出宏可以完成編譯期格式檢查,更加安全。
如果需要輸出某個變量的值,可以使用占位符{}
,例如:
let x = 0; let y = 10; println!("x = {} and y = {}", x, y);
其輸出結果為:
x = 0 and y = 10
為了從控制臺中獲取用戶的輸入,需要使用標準庫std::io
。使用use
語句將該庫引入當前作用域:
use std::io;
我們可以使用io
庫中的函數stdin
:
let mut guess = String::new(); // 創建一個字符串類型的可變變量 io::stdin().read_line(&mut guess).expect("Failed to read line");
stdin
函數返回一個std::io::Stdin
的實例,這代表終端標準輸入句柄的類型。然后調用read_line
方法,可以從標準輸入中讀取一行并存入到guess
變量中去。&
表示這是一個引用,這是一個復雜的特性,我們現在無須了解它。
讀取用戶輸入后,我們需要判斷用戶是否正確輸入了數字。String
類型帶有處理字符串處理的一些方法:
let guess: u32 = guess.trim().parse().expect("Please type a number!");
字符串的 parse
方法將字符串解析成數字。因為這個方法可以解析多種數字類型,因此需要告訴 Rust 具體的數字類型,這里通過 let guess: u32
指定。guess
后的冒號:
告訴 Rust 我們指定了變量的類型。Rust 有一些內建的數字類型,u32 是一個無符號的 32 位整型。trim
方法用于消除回車空格等符號。
上一小節代碼中還有一個expect
沒有分析,而這就涉及到Rust中的錯誤處理機制了。read_line
的返回值類型是io::Result
,它是Result
類型在io
模塊的特化版本。Result
是枚舉類型,其成員為Ok
和Err
,Ok
成員表示操作成功,內部包含成功時產生的值。Err
成員則意味著操作失敗,并且包含失敗的前因后果。
Result
類型的作用是編碼錯誤處理信息。Result
類型像其他類型一樣,擁有定義于其上的方法。io::Result
的實例擁有expect
方法。如果 io::Result
實例的值是 Err
,expect
會導致程序崩潰,并打印參數傳遞給 expect
的信息。如果io::Result
實例的值是 Ok
,expect
會獲取 Ok
中的值并返回。在本例中,這個值是用戶輸入到標準輸入中的字節數。
猜謎游戲需要能夠自動生成隨機數。Rust標準庫中尚未包含隨機數功能,但我們可以通過引入外部crate來獲得隨機數功能。還記得Rust的官方開源倉庫嗎,那里可是有很多寶貝的。打開https://crates.io/
,在搜索框中鍵入rand
來搜索具有隨機數功能的crate,出來的第一個結果就是我們需要的crate。
現在我們將這個庫引入到我們的項目中。打開Cargo.toml
,在[dependencies]
下添加:
[dependencies] rand = "0.8.3"
[dependencies]
告訴 Cargo 本項目依賴了哪些外部 crate 及其版本。
下面使用rand
庫來產生隨機數。首先,使用use
語句引入rand
,use rand::Rng;
。然后調用下列函數產生一個1和100之間的數:
let number = rand::thread_rng().gen_range(1..=100);
猜謎游戲的完整代碼如下。
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..=100); 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; } } } }
其中,涉及控制流操作的loop
、match
、continue
、break
等語法,大家應當能夠望文生義。對于這個完整代碼,大家能夠閱讀并知道每一行干了啥即可,不必糾結于語法細節。
猜謎游戲運行結果如下:
感謝各位的閱讀,以上就是“Rust學習筆記之實現一個猜謎游戲小項目的方法教程”的內容了,經過本文的學習后,相信大家對Rust學習筆記之實現一個猜謎游戲小項目的方法教程這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。