Rust 學習之 mod


Rust 學習之 mod

網上說,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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM