Rust中箱、包和模塊的學習筆記
概述
Rust語言使用模塊系統(tǒng)來組織工程和代碼。模塊系統(tǒng)允許我們將相關的函數(shù)、類型、常量等組織在一起,形成一個邏輯上的單元。通過模塊系統(tǒng),我們可以隱藏實現(xiàn)細節(jié),只暴露必要的接口,從而提高代碼的可讀性和可維護性。Rust的模塊系統(tǒng)還支持路徑依賴和重導出等功能,使得代碼的組織更加靈活和方便。
Rust的模塊系統(tǒng)中有三個非常重要的概念,分別是:箱(Crate)、包(Package)和模塊(Module),下面逐一進行介紹。
箱(Crate)
箱,英文為Crate,是Rust中的編譯單元和構建單元,也是Cargo打包和分發(fā)的基本單位。Crate可以是庫(library crate),也可以是二進制程序(binary crate)。庫crate包含了可以被其他crate使用的代碼,二進制crate則包含了可以執(zhí)行的程序。每個crate都有一個crate root,它是編譯器開始構建crate模塊樹的源文件。對于庫crate,crate root通常是src/lib.rs文件;對于二進制crate,crate root通常是src/main.rs文件。
通過crate,我們可以將代碼進一步拆分成更小的、更易于管理和維護的單元。當在Cargo中創(chuàng)建一個新的項目時,實際上就是在創(chuàng)建一個Crate。通過cargo new my_crate命令,Cargo將為我們初始化一個新的Crate結構,其中包括:源碼目錄、測試文件、Cargo.toml配置文件等。在Rust中,Crate是編譯時的概念,它指代的是編譯后生成的一個單元,可以是一個庫或者一個可執(zhí)行程序。
包(Package)
包,英文為Package,是Cargo用于組織和構建代碼的基本單位。每個Rust項目都包含至少一個Package,并通過名為Cargo.toml的配置文件來描述其屬性和依賴關系。Package的元數(shù)據(jù)存儲在Cargo.toml文件中,這個文件包含了關于Package的基本信息,比如:名稱、版本、作者、描述、許可證等。另外,Cargo.toml還列出了Package的依賴項,這些依賴項是其他Packages或Crates,它們會被Cargo自動下載和構建。

Package通常包含源碼目錄,包括但不限于src目錄下的main.rs或lib.rs。如果項目更復雜,還可以有多個模塊文件和子模塊文件夾。一個Package可以包含一個或多個Crates,但通常情況下,一個簡單的Package會對應一個單一的Crate。當通過cargo build命令構建項目時,最終輸出的二進制文件或庫文件就是這個Crate。
模塊(Module)
模塊,英文為Module,是用于在crate內(nèi)部進行分層和封裝的機制。模塊內(nèi)部又可以包含模塊,從而形成一個樹形結構,也稱為模塊樹。每個crate會自動產(chǎn)生一個與當前crate同名的模塊,作為這個樹形結構的根節(jié)點。模塊是元素(比如:函數(shù)、結構體、trait等)的集合,是一種抽象的概念,而文件則是承載這個概念的實體。
在Rust中,創(chuàng)建新模塊主要有以下三種方式。
1、在一個文件中創(chuàng)建內(nèi)嵌模塊。這可以通過直接使用mod關鍵字來實現(xiàn),模塊的內(nèi)容會被包含在大括號內(nèi)部。
2、獨立的一個文件就是一個模塊,文件名即是模塊名。
3、一個文件夾也可以代表一個模塊。在這種情況下,有兩種方法可以實現(xiàn):
(1)文件夾內(nèi)部需要有一個名為mod.rs的文件,這個文件就是這個模塊的入口。在rustc 1.30版本之前,這是唯一的方法。
(2)在文件夾同級目錄里創(chuàng)建一個與模塊(文件夾)同名的rs文件。在rustc 1.30版本之后,更建議使用這樣的命名方式,以避免項目中存在大量同名的mod.rs文件。
模塊樹
模塊樹是一個邏輯上的分層結構,它反映了源代碼文件的組織方式。每個Rust項目都可以看作一個模塊樹的根,其中包含零個或多個子模塊。每個模塊可以進一步包含其他的子模塊,從而形成嵌套的層次結構。
在下面的示例模塊樹中,lib.rs是crate的根模塊,shapes和math是它的子模塊。circle和rectangle是shapes的子模塊,algebra和geometry是math的子模塊。shapes之所以是模塊,是因為shapes文件夾下有一個mod.rs文件。math之所以是模塊,是因為math同級目錄下有一個同名的math.rs文件。在后面內(nèi)容的介紹當中,我們也會用到這里的示例模塊樹。
project/ ├── src/ │ ├── lib.rs // crate根模塊 │ ├── shapes/ │ │ ├── mod.rs // shapes模塊 │ │ ├── circle.rs │ │ └── rectangle.rs │ ├── math/ │ │ ├── algebra.rs │ │ └── geometry.rs │ └── math.rs // math模塊
模塊路徑
在Rust中,模塊路徑是用于唯一標識模塊中定義的元素(比如:函數(shù)、結構體等)的字符串。模塊路徑由一系列由雙冒號(::)分隔的標識符組成,從crate根開始,一直到指定的項,可以是絕對路徑或相對路徑。
絕對路徑:以crate::開始,表示從crate根開始的完整路徑。在下面的示例代碼中,crate::shapes::circle::Area表示從crate根開始的shapes子模塊、circle子目錄的Area函數(shù)。
use crate::shapes::circle::Area;
相對路徑:直接使用模塊名稱表示同級模塊,或者相對于當前模塊的子模塊。有兩個特殊的標識需要記住,self::表示當前模塊,super::表示當前模塊的父模塊。
// 在shapes/mod.rs中引用circle.rs中的內(nèi)容 use self::circle::Area; // 在circle.rs中引用shapes/mod.rs中定義的公共常量DEFAULT_RADIUS use super::DEFAULT_RADIUS; // 在同一目錄下引用rectangle模塊 use rectangle::Rectangle;
訪問權限
在Rust中,訪問權限是通過pub關鍵字來控制的。默認情況下,如果不加修飾符,模塊中的成員訪問權將是私有的。這意味著,它們只能在定義它們的模塊內(nèi)部被訪問。如果想讓其他模塊能夠訪問某個成員,就需要在該模塊和該成員前加上pub關鍵字來聲明其為公開的。
訪問權限主要有兩種:一種是模塊級的訪問權限,另一種是成員級別的訪問權限。
1、模塊級的訪問權限。公開模塊可以在任何地方被訪問,只要我們知道正確的路徑。私有模塊只能在與其平級的位置,或下級的位置被訪問。也就是說,如果一個模塊是私有的,那么只有在其同級模塊或子模塊中才能引用它。
2、成員級別的訪問權限。使用pub關鍵字標記的成員是公開的,可以在其他模塊中通過路徑來訪問。沒有使用pub關鍵字標記的成員是私有的,只能在定義它們的模塊內(nèi)部訪問。
// 公開模塊
pub mod public_module {
// 公開函數(shù),可以在其他模塊中訪問
pub fn public_function() {
}
// 私有函數(shù),只能在本模塊內(nèi)部訪問
fn private_function() {
}
}
// 私有模塊
mod private_module {
// 這個模塊是私有的,不能在其他模塊中直接訪問
fn private_function() {
}
}
fn main() {
public_module::public_function();
}除此之外,Rust還提供了更細粒度的訪問控制,允許我們指定一個成員僅在crate內(nèi)部可見,或者僅在特定的模塊及其子模塊中可見。pub(crate)表示該成員在當前crate的任何地方都可見,但在外部crate中不可見。pub(in module)表示該成員在指定的模塊及其子模塊中可見,在其他模塊不可見。
// 函數(shù)僅在當前crate內(nèi)可見
pub(crate) fn crate_function() {
}
// 公開模塊
pub mod my_module {
// 函數(shù)僅在當前模塊及其子模塊中可見
pub(in crate::my_module) fn module_function() {
}
pub fn public_function() {
// 可以調(diào)用crate_function
crate::crate_function();
// 可以調(diào)用module_function
module_function();
}
}
// 另一個模塊
mod another_module {
pub fn another_function() {
crate::crate_function();
// 下面的代碼會提示編譯錯誤:function `module_function` is private
super::my_module::module_function();
}
}
fn main() {
crate_function();
}如果模塊中定義了結構體,那么結構體本身以及它的字段默認都是私有的。如果希望結構體的某個字段能夠被外部訪問,則需要在結構體和該字段前均加上pub關鍵字。枚舉類型則不同,只需要在枚舉類型前加上pub關鍵字,而不需要在枚舉成員前加上pub關鍵字。
使用use
use關鍵字用于導入模塊或庫中的元素(比如:函數(shù)、結構體等),以便在當前作用域中使用它們而無需使用完全限定的名稱。use語句通常放在文件的頂部,緊接在模塊聲明之后。
use關鍵字的使用方式主要以下幾種。
1、導入整個模塊??梢允褂胾se來導入整個模塊,這樣我們就可以直接使用該模塊中公開的成員。
// 導入std模塊中的vec模塊
use std::vec;
fn main() {
// 直接使用vec!宏
let value = vec![1, 2, 3];
println!("{:?}", value);
}2、導入特定項??梢允褂胾se來導入模塊中的特定項,而不是整個模塊。
// 只導入HashMap use std::collections::HashMap;
3、重命名導入的項。如果導入的元素在當前作用域中已經(jīng)存在同名項,或者想要使用不同的名稱來引用它,我們可以使用as關鍵字來重命名。
// 重命名HashMap為:MyMap use std::collections::HashMap as MyMap;
4、使用通配符導入。使用*可以導入模塊中所有公開的成員,但需要注意的是,過度使用通配符導入可能會導致名稱沖突和不可預見的行為,因此通常建議明確導入你需要的元素。
// 導入std::collections模塊中的所有公開成員 use std::collections::*;
5、多個use語句可以組合在一起,以提高便捷性和可讀性。
use std::{
fs::File,
io::{self, Write},
};總結
Rust的模塊系統(tǒng)是其代碼組織管理的核心部分,它提供了一種方式來封裝和組織代碼,控制作用域和路徑的私有性,以及導出公共接口。模塊系統(tǒng)使得開發(fā)者能夠構建大型、復雜的應用程序,同時保持代碼的清晰性和可維護性。
到此這篇關于Rust中箱、包和模塊的學習筆記的文章就介紹到這了,更多相關Rust 箱、包和模塊內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

