模塊
與 C++的命名空間和Pyhton的模塊不同,Rust 的模塊更加靈活且作用清晰。Rust 的模塊(mod)用于封裝一個(gè)邏輯塊,mod 可以嵌套定義,設(shè)計(jì)成層次邏輯,且可以指定 mod 的訪問屬性,即私有(private)和公開(pub),兩者又可細(xì)分為:
private
: 該模塊內(nèi)部僅模塊內(nèi)部可見pub(crate)
: 模塊內(nèi)部對(duì)該 crate 可見pub(super)
:模塊內(nèi)部僅對(duì)本級(jí)和上級(jí) mod 可見pub
:該模塊對(duì)全局可見,如果該模塊被上級(jí)包含,則由上級(jí)模塊最終決定最大可見范圍 通常一個(gè)文件名自動(dòng)成為模塊名。對(duì)于文件夾來說,模塊的根節(jié)點(diǎn)為mod.rs
,模塊名則為文件夾的名字
Crate
crate
是 Rust 的代碼單元,也是 Cargo 管理、發(fā)布的最小單元。通常可以包含一個(gè)或多個(gè)模塊。Rust有兩種 crate :庫(Library Crate)和二進(jìn)制(Binary Crate)。
Library Crate
用于提供代碼庫,編譯后的目標(biāo)文件是鏈接庫,即動(dòng)態(tài)庫、靜態(tài)庫等,可用于Rust或第三方語言(如C/C++等)調(diào)用。當(dāng)然Libary crate也可以被其他crate引用,在Cargo.tml 中指定引用信息,從而直接使用改crate的模塊或 API 。大致可以理解為 C/C++ 的庫,例如 stdio.h,string.h等。Binary Crate
用于實(shí)現(xiàn)具體的程序,包含程序入口 main 函數(shù),編譯后為二進(jìn)制的程序,可直接運(yùn)行。可以簡單理解為 C/C++ 的main.c + XX.c
文件,當(dāng)然實(shí)際用起來比它們更加優(yōu)雅。
Package
Package
用于管理 Crate, 每個(gè) package 的根目錄包含一個(gè)文件 Cargo.toml
,用于指定 Package 的元信息,如作者、版本、features、依賴、目標(biāo)編譯平臺(tái)。Cargo 可將 Package 發(fā)布到 crate.io。一個(gè) Package 可以包含多個(gè)成員(members)
Cargo
Cargo 是 Rust 的包管理工具和構(gòu)建系統(tǒng)。它在 Rust 開發(fā)中起著至關(guān)重要的作用,主要有以下功能特點(diǎn):
- 提供快捷的工程創(chuàng)建、編譯、測(cè)試、程序下載、運(yùn)行、文檔生成等命令
- 版本控制、依賴控制功能
- 工程管理、發(fā)布功能
- 統(tǒng)一工程結(jié)構(gòu),便于理解和維護(hù),提高開發(fā)效率和代碼質(zhì)量。
其功能遠(yuǎn)比 傳統(tǒng)的 Makefile 或 CMake 豐富,但使用卻更加簡單高效。
features
features 在 Cargo.tml 中定義,類似 C/C++ 中編譯宏的作用,可以選擇性編譯開啟指定 feature 的代碼段,從而達(dá)到縮小代碼體積、實(shí)現(xiàn)不同的功能、滿足不同的平臺(tái)等功能。
枚舉
Rust 的枚舉與 C/C++ 的兼容,但表現(xiàn)形式更加豐富。不僅允許指定數(shù)字作為枚舉值,同時(shí)也允許枚舉項(xiàng)能附帶一個(gè)其他類型的對(duì)象,如常用的基本類型、其他枚舉、結(jié)構(gòu)體、元組等類型,使用枚舉能更加輕松直接的描述對(duì)象特征和邏輯。使得業(yè)務(wù)邏輯更加簡單清晰。
pub enum {
Monday,
Tuesday,
...
}
enum Fruit{
Apple = 0,
Orange = 1
}
pub enum {
Foo,
Fruit(Fruit), /* 附帶另外的枚舉值 */
Id(u32), /* 附帶一個(gè) u32 的數(shù)字 */
Human((u8, String)), /* 附帶一個(gè)元組 */
Stu(Student), /* 附帶一個(gè)結(jié)構(gòu)體 */
}
Rust 有兩個(gè)特別重要的枚舉,經(jīng)常在代碼中可以看到,分別是:
Result
:Reuslt 常用于表示結(jié)果,定義如下:
enum Result {
Ok(T),
Err(E),
}
- T 和 E 分別表示正常和異常返回的類型。該定義用于表示正常返回和異常情況返回的結(jié)果,各自附帶一個(gè)類型用于返回有用的信息。該設(shè)計(jì)能避免像 C 中常使用的數(shù)字或宏返回錯(cuò)誤值。
Option
:用于表示有無,定義如下:
enum Option {
None,
Some(T),
}
- T 表示數(shù)據(jù)存在時(shí)候的數(shù)據(jù)類型。使用 Option 可以避免使用 null 指針之類不安全的方式來表示有無返回對(duì)象。能提高代碼可靠性、同時(shí)擁有高的執(zhí)行效率。
#![no_std]
no_std
環(huán)境區(qū)別于 std
, no_std
通常用于嵌入式裸機(jī)環(huán)境, 降低標(biāo)準(zhǔn)庫所占用的程序空間。
no_std 通常不包含操作系統(tǒng)的基本 api,如文件系統(tǒng)、網(wǎng)絡(luò)、多線程等接口。但其仍然提供了一些常用的基本接口模塊,如基本數(shù)據(jù)類型,算術(shù)運(yùn)算,位操作、裸地址讀寫等常用接口。在嵌入式裸機(jī)系統(tǒng)工程搭建時(shí),需要在主模塊中添加 #![no_std]
來告訴編譯起不要鏈接 std
crate。同時(shí)對(duì)于no_std
工程來說,需要自己實(shí)現(xiàn) panic
接口。
Traits
Rust 是一門函數(shù)式編程的語言,trait
在該方案中發(fā)揮了巨大的作用。trait
可翻譯為特征,用于描述對(duì)象所具備的 api 能力或?qū)傩裕部勺鳛闃?biāo)記,用于提示編譯器在編譯代碼時(shí)確定邏輯是否合法,且沒有任何運(yùn)行時(shí)的消耗,也不占用程序空間。
不同于面向?qū)ο缶幊讨械睦^承的思想,trait
主要用來定義共享的行為,可以在模板中作為一種約束,避免模塊實(shí)例化有不符合該 trait 約束的對(duì)象引入,保證在編譯能發(fā)現(xiàn)非法的模板使用。Rust 保證在實(shí)現(xiàn)靈活的編程時(shí),又能安全、高效的定義接口,避免用戶使用錯(cuò)誤,同時(shí)也能統(tǒng)一接口,極大得方便移植,在常見的 Rust 嵌入式驅(qū)動(dòng)中可以經(jīng)常看到 trait
的使用。
另外常見的標(biāo)記類的 trait
有 Send
, Sync
, Unpin
,Clone
等
異步/Future
在 Rust 中,實(shí)現(xiàn)了 Future
trait 的對(duì)象代表可能尚未完成計(jì)算的值。Future 有一個(gè)關(guān)聯(lián)的 Output 類型,它最終會(huì)解析為這個(gè)類型的值。Future trait 的定義特征是 poll 函數(shù)。
簡單的理解可以認(rèn)為:Future 表示一個(gè)異步操作的潛在結(jié)果。它允許你以一種非阻塞的方式執(zhí)行異步任務(wù),并在任務(wù)完成時(shí)獲取結(jié)果。不像 C 中常使用注冊(cè)的 callback
函數(shù)那樣需要程序員清晰得去理解多任務(wù)間狀態(tài)邏輯。Future 讓 Rust 異步程序邏輯更加線性化,方便編寫和理解。以下展示一個(gè)簡單的 異步示例:
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
struct MyFuture {
// 一些狀態(tài),例如異步操作的計(jì)數(shù)器
counter: u32,
}
impl Future for MyFuture {
type Output = u32;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll {
if self.get_mut().counter < 5 {
self.get_mut().counter += 1;
Poll::Pending
} else {
Poll::Ready(self.get_mut().counter)
}
}
}
在這個(gè)示例中,MyFuture 是一個(gè)自定義的 Future,它在計(jì)數(shù)器達(dá)到 5 之前一直處于 Pending 狀態(tài),當(dāng)計(jì)數(shù)器達(dá)到 5 時(shí),返回 Poll::Ready(counter)。總之,F(xiàn)uture trait 和 poll 函數(shù)是 Rust 異步編程的基礎(chǔ),它們提供了一種強(qiáng)大的方式來處理異步操作和構(gòu)建高效的異步程序。
零成本抽象
零成本抽象也是 Rust 的一個(gè)重要的特點(diǎn)。通常在高級(jí)語言中,對(duì)于抽象級(jí)別越高的對(duì)象,可能需要消耗更多的程序空間或運(yùn)行時(shí)間。但在 Rust 中,很多高級(jí)抽象都是零成本的,不占用任何運(yùn)行時(shí)間和程序空間。常見如下
- 迭代器
- 閉包
- 智能指針
- 枚舉
- 零大小結(jié)構(gòu)體
這些常用的抽象可以放心在嵌入式中使用,不會(huì)占用大量的空間,且執(zhí)行效率與直接手寫的代碼幾乎一致。
附錄
Introduction - The Cargo Book (rust-lang.org)
The Rust Programming Language
The Rustonomicon