Rust中使用模塊組織代碼

[TOC]

Rust中使用模塊組織代碼


Rust中的模塊化編程

自上個世紀 90 年代以來裕坊,軟件工程的復(fù)雜性越來越高谴餐,程序漸漸從一個人的獨狼開發(fā)轉(zhuǎn)為多人團隊協(xié)作開發(fā)累舷。在今天蝇摸,通過 Github 或中心化的代碼分發(fā)網(wǎng)站橘洞,我們可以輕松的在一個軟件工程中同時引入世界各地的開發(fā)者開發(fā)的代碼捌袜,我們與同事在同一個工程目錄下并行開發(fā)不同的程序功能,或者在不拷貝代碼的前提下將一個工程中的代碼在另一個工程中復(fù)用炸枣。這一切都是因為模塊化編程虏等。

模塊化編程弄唧,是強調(diào)將計算機程序的功能分離成獨立的和可相互改變的“模塊”的軟件設(shè)計技術(shù),它使得每個模塊都包含著執(zhí)行預(yù)期功能的一個唯一方面所必需的所有東西霍衫,復(fù)雜的系統(tǒng)被分割為小塊的獨立代碼塊候引。

Rust 項目的代碼組織包含以下三個基本概念:

  • Package(包)
  • Crate(箱)
  • Module(模塊)

Package

Package 用于管理一個或多個 Crate。創(chuàng)建一個 Package 的方式是使用 cargo new敦跌,我們來看看一個 Package 包含哪些文件澄干。

$ cargo new my-project
     Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs

當(dāng)我們輸入命令時,Cargo 創(chuàng)建了一個目錄以及一個 Cargo.toml 文件柠傍,這就是一個 Package麸俘。默認情況下,src/main.rs 是與 Package 同名的二進制 Crate 的入口文件惧笛,因此我們可以說我們現(xiàn)在有一個 my-project Package 以及一個二進制 my-project Crate疾掰。同樣,如果在創(chuàng)建 Package 的時候帶上 --lib徐紧,那么 src/lib.rs 將是它的 Crate 入口文件静檬,且它是一個庫 Crate。

如果我們的 src 目錄中同時包含 main.rslib.rs并级,那么我們將在這個 Package 中同時得到一個二進制 Crate 和一個庫 Crate拂檩,這在開發(fā)一些基礎(chǔ)庫時非常有用,例如你使用 Rust 中實現(xiàn)了一個 MD5 函數(shù)嘲碧,你既希望這個 MD5 函數(shù)能作為庫被別人引用稻励,又希望你能獲得一個可以進行 MD5 計算的命令行工具:那就同時添加 main.rslib.rs 吧!

Crate

Crate 是 Rust 的最小編譯單元愈涩,即 Rust 編譯器是以 Crate 為最小單元進行編譯的望抽。Crate 在一個范圍內(nèi)將相關(guān)的功能組合在一起,并最終通過編譯生成一個二進制或庫文件履婉。例如煤篙,我們在上一章中實現(xiàn)的猜數(shù)字游戲就使用了 rand 依賴,這個 rand 就是一個 Crate毁腿,并且是一個庫的 Crate辑奈。

Module

Module 允許我們將一個 Crate 中的代碼組織成獨立的代碼塊,以便于增強可讀性和代碼復(fù)用已烤。同時鸠窗,Module 還控制代碼的可見性,即將代碼分為公開代碼和私有代碼胯究。公開代碼可以在項目外被使用稍计,私有代碼則只有項目內(nèi)部的代碼才可以訪問。定義一個模塊最基本的方式是使用 mod 關(guān)鍵字:

mod mod1 {
     pub mod mod2 {
          pub const MESSAGE: &str = "Hello World!"
          // ...
     }
     // ...
}

fn main() {
     println!(mod1::mod2::MESSAGE);
}

使用pub改變可見性

Rust 中模塊內(nèi)部的代碼裕循,結(jié)構(gòu)體臣嚣,函數(shù)等類型默認是私有的净刮,但是可以通過 pub 關(guān)鍵字來改變它們的可見性。通過選擇性的對外可見來隱藏模塊內(nèi)部的實現(xiàn)細節(jié)茧球。

比較常用的三種 pub 寫法:

  • pub:成員對模塊可見
  • pub(self):成員對模塊內(nèi)的子模塊可見
  • pub(crate):成員對整個 crate 可見

如果不使用 pub 聲明庭瑰,成員默認的可見性是私有的:

mod mod1 {
    pub const MESSAGE: &str = "Hello World!";
    const NUMBER: u32 = 42;

    pub(self) fn mod1_pub_self_fn() {
        println!("{}", NUMBER);
    }

    pub(crate) enum CrateEnum {
        Item = 4,
    }

    pub mod mod2 {
        pub const MESSAGE: &str = "Hello World!";

        pub fn mod2_fn() {
            super::mod1_pub_self_fn();
        }
    }
}

fn main() {
    println!("{}", mod1::MESSAGE);
    println!("{}", mod1::mod2::MESSAGE);
    mod1::mod2::mod2_fn();
    println!("{}", mod1::CrateEnum::Item as u32);
}

結(jié)構(gòu)體的可見性

結(jié)構(gòu)體中的字段和方法默認是私有的星持,通過加上 pub 修飾語可使得結(jié)構(gòu)體中的字段和方法可以在定義結(jié)構(gòu)體的模塊之外被訪問抢埋。要注意,與結(jié)構(gòu)體同一個模塊的代碼訪問結(jié)構(gòu)體中的字段和方法并不要求該字段是可見的:

mod mod1 {
    pub struct Person {
        pub name: String,
        nickname: String,
    }

    impl Person {
        pub fn new(name: &str, nickname: &str) -> Self {
            Person {
                name: String::from(name),
                nickname: String::from(nickname),
            }
        }

        pub fn say_nick_name(&self) {
            println!("{}", self.nickname);
        }
    }
}

fn main() {
    let p = mod1::Person::new("jack", "baby");
    println!("{}", p.name);
    // println!("{}", p.nickname); // 不能訪問 nickname
    p.say_nick_name();
}

使用use綁定模塊成員

正常情況下當(dāng)我們試圖從模塊內(nèi)中訪問其成員時督暂,需要輸入完整的路徑揪垄,例如使用 std::fs::read 從磁盤上讀取文件:

fn main() {
    let data = std::fs::read("src/main.rs").unwrap();
    println!("{}", String::from_utf8(data).unwrap());
}

可以使用 use 關(guān)鍵詞將完整路徑綁定到一個新的名稱,這可以減少重復(fù)代碼:

use std::fs;

fn main() {
    let data = fs::read("src/main.rs").unwrap();
    println!("{}", String::from_utf8(data).unwrap());
}

可以使用 as 關(guān)鍵字將導(dǎo)入綁定到一個其他名稱逻翁,它通常用在有多個不同模塊都定義了相同名字的成員時使用:

use std::fs as stdfs;

fn main() {
    let data = stdfs::read("src/main.rs").unwrap();
    println!("{}", String::from_utf8(data).unwrap());
}

使用super與self簡化模塊路徑

除了使用完整路徑訪問模塊內(nèi)的成員饥努,還可以使用 super 與 self 關(guān)鍵字相對路徑對模塊進行訪問:

  • super:上層模塊
  • self:當(dāng)前模塊

當(dāng)上層模塊,當(dāng)前模塊或子模塊中擁有相同名字的成員時八回,使用 super 與 self 可以消除訪問時的歧義:

fn function() {
    println!("function");
}

pub mod mod1 {
    pub fn function() {
        super::function();
    }

    pub mod mod2 {
        fn function() {
            println!("mod1::mod2::function");
        }

        pub fn call() {
            self::function();
        }
    }
}

fn main() {
    mod1::function();
    mod1::mod2::call();
}

項目目錄層次結(jié)構(gòu)

將模塊映射到文件

使用 mod <路徑> 語法酷愧,將一個 rust 源碼文件作為模塊內(nèi)引入:

src
├── main.rs
└── mod1.rs

mod1.rs

pub const MESSAGE: &str = "Hello World!";

main.rs

mod mod1;

fn main() {
    println!("{}", mod1::MESSAGE);
}

將模塊映射到文件夾

當(dāng)一個文件夾中包含 mod.rs 文件時,該文件夾可以被作為一個模塊:

src
├── main.rs
└── mod1
    └── mod.rs

mod1/mod.rs

pub const MESSAGE: &str = "Hello World!";

main.rs

mod mod1;

fn main() {
    println!("{}", mod1::MESSAGE);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缠诅,一起剝皮案震驚了整個濱河市溶浴,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌管引,老刑警劉巖士败,帶你破解...
    沈念sama閱讀 218,941評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異褥伴,居然都是意外死亡谅将,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評論 3 395
  • 文/潘曉璐 我一進店門重慢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饥臂,“玉大人,你說我怎么就攤上這事似踱∩帽剩” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評論 0 356
  • 文/不壞的土叔 我叫張陵屯援,是天一觀的道長猛们。 經(jīng)常有香客問我,道長狞洋,這世上最難降的妖魔是什么弯淘? 我笑而不...
    開封第一講書人閱讀 58,851評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮吉懊,結(jié)果婚禮上庐橙,老公的妹妹穿的比我還像新娘假勿。我一直安慰自己,他們只是感情好态鳖,可當(dāng)我...
    茶點故事閱讀 67,868評論 6 392
  • 文/花漫 我一把揭開白布转培。 她就那樣靜靜地躺著,像睡著了一般浆竭。 火紅的嫁衣襯著肌膚如雪浸须。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評論 1 305
  • 那天邦泄,我揣著相機與錄音删窒,去河邊找鬼。 笑死顺囊,一個胖子當(dāng)著我的面吹牛肌索,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播特碳,決...
    沈念sama閱讀 40,414評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼诚亚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了午乓?” 一聲冷哼從身側(cè)響起站宗,我...
    開封第一講書人閱讀 39,319評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎硅瞧,沒想到半個月后份乒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡腕唧,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年或辖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枣接。...
    茶點故事閱讀 40,096評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡颂暇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出但惶,到底是詐尸還是另有隱情耳鸯,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評論 5 346
  • 正文 年R本政府宣布膀曾,位于F島的核電站县爬,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏添谊。R本人自食惡果不足惜财喳,卻給世界環(huán)境...
    茶點故事閱讀 41,437評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧耳高,春花似錦扎瓶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至碌燕,卻和暖如春误证,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背陆蟆。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評論 1 271
  • 我被黑心中介騙來泰國打工雷厂, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留惋增,地道東北人叠殷。 一個月前我還...
    沈念sama閱讀 48,308評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像诈皿,于是被迫代替她去往敵國和親林束。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,037評論 2 355

推薦閱讀更多精彩內(nèi)容