Rust 學習之 mod
Rust 學習之 mod
- 作者:suhanyujie
- 來源:https://github.com/suhanyujie/rust-cookbook-note
- tags:Rust 模組系統,mod 系統,Rust mod,Rust module
- tips:如有不當之處,還請指正~
網上說,Rust 的學習曲線不像其他語言那樣,用一句話描述就是:從入門到入門。這用在我身上很準確,我先後曾不止兩次入門,每兩次之間又都相隔數月,以至於經常需要翻閱 Rust 官方書 《Rust 程式語言》。
不過說真的,隨著自學的逐步加深,會覺得越來越喜歡 Rust(可能是沒有在實際專案中深入的使用導致),但既然很喜歡,那就藉著這份熱情,好好地瞭解“她”。
從去年到現在,差不多一年左右,除了把官方書看完了,還利用碎片時間將範長春前輩的《深入淺出 Rust》看完。大部分是在地鐵上看的,所以實踐的不夠,這篇記錄 Rust mod 也是其中一篇筆記。
在閱讀該篇筆記之前,需要你先認真讀完官方書的 mod 章節
由於 Rust 提供了非常好用的工具鏈 —— cargo,使用者只需簡單的 cargo new pro_name
即可建立一個目錄很規範的可執行程式的專案,使用者做的只需將精力放在開發邏輯上,大大減少了心智負擔。而這也能滿足很多型別的中小專案。
而在編寫大型的專案時,又可以通過 Rust 的模組化支援來很好的實現。通過 Rust 模組的學習,我們可以看出,Rust 模組很強大並且不失靈活。例如:
1.你可以在單個檔案中編寫多個模組。
// src/notes/test_module/single_mod.rs pub mod single_mod { pub mod my_mod1 { pub fn mod1_func1() { println!("file:single_mod-single_mod-my_mod1-mod1_func1"); } } pub fn func_0() { // 呼叫父級模組下的函式 println!("呼叫父級模組下的函式:"); super::level1_mod1::mod1_func1(); // 呼叫同級下的模組下的函式 println!("呼叫同級下的模組下的函式:"); my_mod1::mod1_func1(); println!("file:single_mod-single_mod-func_0"); } } pub mod level1_mod1 { pub fn mod1_func1() { println!("file:single_mod-level1_mod1-mod1_func1"); } }
2.也可以將一個 rs 檔案作為一個模組。將一個檔案作為一個模組,也就意味著裡面可能會有函式宣告、型別宣告、trait 宣告等。
// 函式宣告
pub fn one_file_func() {
println!("file:one_file-one_file_func");
}
trait Human {
fn speak();
}
// 型別宣告
#[derive(Debug)]
pub struct Stu {
id: i32,
name: String,
age: u8,
}
impl Human for Stu {
fn speak() {
println!("I speak Chinese.")
}
}
impl Stu {
pub fn new() -> Stu {
Stu {
id: 1,
name: String::from("張太一"),
age: 24,
}
}
}
3.在一個 crate 中你可以做到多個模組、子模組的巢狀。
// src/notes/test_module/single_mod.rs
pub mod single_mod {
pub mod my_mod1 {
pub fn mod1_func1() {
println!("file:single_mod-single_mod-my_mod1-mod1_func1");
}
}
pub fn func_0() {
// 呼叫父級模組下的函式
println!("呼叫父級模組下的函式:");
super::level1_mod1::mod1_func1();
// 呼叫同級下的模組下的函式
println!("呼叫同級下的模組下的函式:");
my_mod1::mod1_func1();
println!("file:single_mod-single_mod-func_0");
}
}
單檔案多模組
先說單個 rs 檔案中的模組。在一個 rs 檔案中,我們可以通過 mod 關鍵字新建很多個模組,例如 single_mod.rs 中的示例程式碼。
這種比較適合小型的工具類的程式,不需要太多檔案,就能在有限的檔案中,拆分 module。侷限性就是不適合程式碼多的專案,拆分不是很清晰。
單倉庫多模組
這裡的單倉庫,本意是指在單個的 crate 中。前兩天剛好看到了一個文章 —— Rust module 系統詳解,這篇文章由淺入深的闡釋了 crate 和 module 的聯絡。
在一個 crate 中,我們可以宣告很多個 module。這裡我們以一個 Rust bin 程式作為示例,用 cargo new --bin crate_module
建立一個專案框架,使用 tree .
可檢視其目錄如下所示:
.
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
這個 crate 的根模組可以認為是從 src 目錄開始,當我們要在 main.rs 中呼叫 user_service.rs 中的方法/函式時,需要先在 main.rs 檔案中引入 —— mod services;
,使用了這個語句後,Rust module 系統會有兩個選擇:
- 1.在當前目錄下尋找 services.rs 檔案。因為一個 rs 檔案可以看做一個 module
- 2.在當前目錄下尋找 services/mod.rs 檔案。此時 services 可以看做是一個名稱空間,它背後,可以有很多的 module(通過 mod.rs 檔案管理)
而在我們的“crate_module”例子中,恰好是第 2 種方式 —— 載入 services/mod.rs 檔案。
增加了 services 目錄後的檔案列表如下:
.
├── Cargo.lock
├── Cargo.toml
├── src
│ ├── main.rs
│ └── services
│ ├── mod.rs
│ └── user_service.rs
因此,在專案的 src 目錄下,main.rs 中如果要引入一個 helper.rs 檔案,我們只需在 main.rs 檔案中這樣做:mod helper;
,這樣在 main.rs 中就能使用 helper.rs 檔案中匯出的型別、函式等內容。
mod helper;
use helper::Helper;
fn main() {
let h1 = Helper::new();
println!("{:?}", h1);
}
workspace
上面一節所說的將許多的 module 分散在不同的目錄、檔案中,可以將專案拆分開,以寫出更加抽象、可複用的程式碼。
當隨著專案開發的深入,業務的增長,程式碼越來越多,就會導致 crate 持續增大,我們可能會希望將其拆分成多個 crate,這有些類似於 web 開發中的微服務,將服務抽象進行抽象,拆分成不同的模組和型別,通過介面來進行呼叫。Rust 中 workspace 的概念就是類似的作用。
在官方的 cargo 書上,對 workspace 也有比較詳細的介紹
更加詳細的 workspace 實踐,可以參考這裡的例項。
其他
reference
- Rust 官方書 https://doc.rust-lang.org/book/
- Rust 官方書中譯版 https://kaisery.github.io/trpl-zh-cn
- Rust module 系統詳解 http://www.sheshbabu.com/posts/rust-module-system/