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/