Rust 語言具備記憶體安全和高效能的特性,使其成為系統程式設計的理想選擇。本文除了介紹 Rust 的特性和應用場景外,也探討了 Cargo 的使用方法,包含建立新專案、管理相依性、執行測試以及發布函式庫等。Cargo 作為 Rust 的套件管理工具,不僅簡化了開發流程,也提升了程式碼的可維護性和重用性,是 Rust 開發者不可或缺的工具。瞭解 Cargo 的運作方式,能幫助開發者更有效率地建構和管理 Rust 專案,並充分利用 Rust 生態圈的資源。
Rust 介紹與應用場景
Rust 是一種現代系統級程式語言,具備先進的安全特性和零成本抽象。相較於其他程式語言,Rust 在安全性、效能和平行處理方面有明顯優勢。Rust 的學習曲線較陡,但本文將幫助讀者克服這些困難。
1.2.4 Rust 與其他流行語言的比較
| 語言 | 程式正規化 | 型別系統 | 記憶體管理 | 主要特性 |
|---|---|---|---|---|
| Rust | 平行、函式式、泛型、命令式 | 靜態、強型別 | RAII、顯式管理 | 安全性、效能、非同步處理 |
| C | 命令式 | 靜態、弱型別 | 顯式管理 | 效率、可移植性、低階記憶體管理 |
| C++ | 命令式、物件導向、泛型、函式式 | 靜態、混合型別 | RAII、顯式管理 | 效率、可移植性、低階記憶體管理 |
| C# | 物件導向、命令式、事件驅動、函式式、反射式、平行 | 靜態、動態、強型別 | 垃圾回收 | Microsoft 平台支援、大型生態系統、先進語言特性 |
| JavaScript | 原型、函式式、命令式 | 動態、鴨子型別、弱型別 | 垃圾回收 | 廣泛支援、非同步處理 |
| Java | 泛型、物件導向、命令式、反射式 | 靜態、強型別 | 垃圾回收 | 位元組碼為基礎的 Java 虛擬機器、大型生態系統 |
| Python | 函式式、命令式、物件導向、反射式 | 動態、鴨子型別、強型別 | 垃圾回收 | 直譯式、高可移植性、廣泛使用 |
| Ruby | 函式式、命令式、物件導向、反射式 | 動態、鴨子型別、強型別 | 垃圾回收 | 簡潔的語法、簡單的平行模型 |
| TypeScript | 函式式、泛型、命令式、物件導向 | 靜態、動態、鴨子型別、混合型別 | 垃圾回收 | 型別檢查、JavaScript 相容性、非同步處理 |
內容解密:
此表格比較了 Rust 與其他流行程式語言的主要特性。Rust 的靜態強型別系統和 RAII(資源取得即初始化)記憶體管理模型使其在安全性和效能方面具有明顯優勢。
何時使用 Rust?
Rust 是一種系統程式語言,適用於低階系統程式設計,類別似於 C 或 C++。Rust 在需要安全性和效能的場景中表現出色,例如:
- 程式碼加速:Rust 可以加速其他語言(如 Python、Ruby 或 Elixir)的函式。
- 平行系統:Rust 的安全性保證適用於平行程式碼,使其成為高效能平行系統的理想選擇。
- 密碼學:Rust 適合實作密碼學演算法。
- 嵌入式程式設計:Rust 編譯出的二進位制檔案捆綁了所有依賴項,使其適合嵌入式系統。
- 敵對環境:在安全性至關重要的情況下,Rust 的保證是完美的選擇。
- 效能關鍵:Rust 在安全性和效能之間取得了良好的平衡。
- 字串處理:Rust 使編寫不易溢位的字串處理程式碼變得容易。
- 取代舊版 C 或 C++:Rust 是取代舊版 C 或 C++ 的極佳選擇。
- 安全的網頁程式設計:Rust 可以針對 Wasm,讓我們能夠以 Rust 的安全性和強型別檢查來建構網頁應用程式。
程式碼範例
// 使用 Rust 編寫一個簡單的函式
fn greet(name: &str) {
println!("Hello, {}!", name);
}
fn main() {
greet("Rust");
}
內容解密:
此範例展示瞭如何使用 Rust 編寫一個簡單的 greet 函式,並在 main 函式中呼叫它。Rust 的語法簡潔明瞭,且具備記憶體安全保證。
必備工具
本文包含一系列程式碼範例,可在 MIT 許可下免費取得。要取得這些範例,您需要一台連網的電腦,安裝有支援的作業系統和表格 1.2 中討論的工具。
| 名稱 | 描述 |
|---|---|
| git | 本文的原始碼儲存在 GitHub 上公開的 Git 儲存函式庫中。 |
| rustup | Rust 的工具,用於管理 Rust 元件,包括 rustc 和其他元件。 |
| gcc 或 clang | 需要安裝 GNU 編譯器套件(GCC)或 Clang 以編譯某些程式碼範例。 |
使用 Cargo 進行專案管理
在深入瞭解 Rust 語言之前,我們需要先熟悉使用 Rust 開發所需的基本工具。雖然這看似繁瑣,但掌握這些工具對於成功至關重要。這些工具是由 Rust 語言的創造者為使用者設計的,旨在簡化開發流程,因此瞭解其用途將帶來長期的好處。
Rust 的套件管理工具稱為 Cargo,它是 Rust 編譯器 rustc、https://crates.io 登入檔以及其他許多 Rust 工具的介面。嚴格來說,不使用 Cargo 也可以使用 Rust 和 rustc,但對於大多數人來說,這並不推薦。
在使用 Rust 開發時,你可能會花很多時間使用 Cargo 和與 Cargo 相關的工具。因此,熟悉 Cargo 的使用方法和最佳實踐非常重要。在後續章節中,我們將提供更多關於如何進一步提高 Cargo 與社群 crate 實用性的建議和細節。
Cargo 簡介
為了展示 Cargo 的功能,讓我們來一探究竟,並瞭解它的典型用法。強烈建議你跟隨本章節的步驟實際操作(理想情況下是在終端機中執行相關命令)。這樣做,即使你已經熟悉 Cargo,也可能會發現新的功能。
基本用法
首先,執行 cargo help 來列出可用的命令:
$ cargo help
Rust's package manager
USAGE:
cargo [+toolchain] [OPTIONS] [SUBCOMMAND]
OPTIONS:
-V, --version Print version info and exit
--list List installed commands
--explain <CODE> Run `rustc --explain CODE`
-v, --verbose Use verbose output (-vv very verbose/build.rs output)
-q, --quiet No output printed to stdout
--color <WHEN> Coloring: auto, always, never
--frozen Require Cargo.lock and cache are up to date
--locked Require Cargo.lock is up to date
--offline Run without accessing the network
-Z <FLAG>... Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details
-h, --help Prints help information
Some common cargo commands are (see all commands with --list):
build, b Compile the current package
check, c Analyze the current package and report errors, but don't build object files
clean Remove the target directory
doc Build this package's and its dependencies' documentation
new Create a new cargo package
init Create a new cargo package in an existing directory
run, r Run a binary or example of the local package
test, t Run the tests
bench Run the benchmarks
update Update dependencies listed in Cargo.lock
search Search registry for crates
publish Package and upload this package to the registry
install Install a Rust binary. Default location is $HOME/.cargo/bin
uninstall Uninstall a Rust binary
See 'cargo help <command>' for more information on a specific command.
如果你自己執行這個命令,你的輸出可能會略有不同,取決於你安裝的 Cargo 版本。如果你沒有看到類別似的輸出,你可能需要驗證你的 Cargo 安裝是否正常。請參考附錄以瞭解如何安裝 Cargo 的詳細資訊。
建立新的應用程式或函式庫
Cargo 有一個內建的樣板產生器,可以建立一個 “Hello, world!” 應用程式或函式庫,從而節省你開始專案的時間。要開始,請在你的開發目錄中(個人喜歡使用 ~/dev)執行以下命令:
$ cargo new dolphins-are-cool
Created binary (application) `dolphins-are-cool` package
這個命令會建立一個名為 dolphins-are-cool 的新樣板應用程式(你可以將名稱改為任何你想要的)。讓我們快速檢視一下輸出的內容:
$ cd dolphins-are-cool/
$ tree
.
├── Cargo.toml
└── src
└── main.rs
1 directory, 2 files
在這段程式碼中,我們看到 Cargo 建立了兩個檔案:
Cargo.toml,這是新應用程式的 Cargo 組態檔案,以 TOML 格式儲存。src目錄下的main.rs,它代表了我們新應用程式的入口點。
提示:Tom’s Obvious, Minimal Language (TOML) 是一種被許多 Rust 相關工具使用的組態檔案格式。有關 TOML 的詳細資訊,請參考 https://toml.io。
接下來,使用 cargo run 編譯並執行新建立的應用程式:
$ cargo run
內容解密:
cargo new dolphins-are-cool:這個命令使用 Cargo 建立一個新的 Rust 專案,名為dolphins-are-cool。預設情況下,Cargo 會建立一個可執行的二進位制應用程式。Cargo.toml:這是專案的組態檔案,用於定義專案的中繼資料和相依性。src/main.rs:這是應用程式的入口點,包含了應用程式的主要邏輯。cargo run:這個命令編譯並執行應用程式。它首先檢查是否有變更,如果有,則重新編譯專案,然後執行產生的二進位制檔案。
透過這些步驟,我們成功地使用 Cargo 建立並執行了一個新的 Rust 應用程式。Cargo 的強大功能和易用性使得管理 Rust 專案變得更加簡單和高效。
為何選擇 Cargo?
Cargo 不僅僅是一個套件管理器,它還簡化了編譯、測試和佈署 Rust 專案的過程。透過使用 Cargo,開發者可以輕鬆地管理專案相依性、編譯專案、執行測試以及發布函式庫或應用程式。
管理相依性
Cargo 使得管理專案相依性變得非常簡單。只需要在 Cargo.toml 檔案中指定所需的 crate(Rust 的套件稱為 crate),Cargo 就會自動下載並編譯這些 crate。
編譯與測試
使用 cargo build 可以編譯專案,而 cargo test 可以執行專案中的測試。這些命令簡化了開發流程,使得開發者可以專注於編寫程式碼。
發布函式庫或應用程式
當專案完成後,可以使用 cargo publish 將函式庫發布到 crates.io,這是 Rust 社群廣泛使用的 crate 登入檔。這使得其他開發者可以輕鬆地找到並使用你的函式庫。
Cargo 專案管理
Cargo 是 Rust 程式語言的專案管理工具,負責處理專案的建置、測試和相依性管理。本章節將介紹 Cargo 的基本使用方式和進階功能。
建立新專案
使用 cargo new 命令可以建立新的 Rust 專案。預設情況下,Cargo 會建立一個可執行檔專案。如果加上 --lib 引數,則會建立一個函式庫專案。
$ cargo new dolphins-are-cool
$ cd dolphins-are-cool/
$ cargo run
Compiling dolphins-are-cool v0.1.0 (/Users/brenden/dev/dolphins-are-cool)
Finished dev [unoptimized + debuginfo] target(s) in 0.59s
Running `target/debug/dolphins-are-cool`
Hello, world!
內容解密:
cargo new命令用於建立新的 Rust 專案。cargo run命令用於編譯並執行專案。
建立函式庫專案
使用 cargo new --lib 命令可以建立新的函式庫專案。
$ cargo new narwhals-are-real --lib
Created library `narwhals-are-real` package
$ cd narwhals-are-real/
$ tree
.
├── Cargo.toml
└── src
└── lib.rs
1 directory, 2 files
內容解密:
--lib引數指定建立函式庫專案。Cargo.toml檔案包含專案的設定資訊。src/lib.rs檔案是函式庫的進入點。
建置、執行和測試
Cargo 提供了多個命令用於建置、執行和測試專案。
| 命令 | 描述 |
|---|---|
build | 編譯並連結專案,產生最終目標檔 |
check | 檢查程式碼的有效性,但不產生目標檔 |
test | 編譯並執行測試 |
run | 編譯並執行目標二進位檔 |
$ cargo test
Finished test [unoptimized + debuginfo] target(s) in 0.00s
Running target/debug/deps/narwhals_are_real-3265ca33d2780ea2
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out;
finished in 0.00s
內容解密:
cargo test命令用於執行測試。- 測試結果顯示測試透過的數量和時間。
切換工具鏈
Rust 提供了多個工具鏈,包括 stable、beta 和 nightly。可以使用 +channel 選項切換工具鏈。
$ cargo +stable test
$ cargo +nightly test
內容解密:
+channel選項用於切換工具鏈。- 需要先安裝對應的工具鏈,例如
rustup toolchain install nightly。
相依性管理
Rust 的相依性管理是透過 Cargo.toml 檔案進行管理。Crates.io 是 Rust 的套件註冊中心,提供了大量的套件。
[dependencies]
dryoc = "0.4.0"
內容解密:
[dependencies]段落用於指定相依性套件。dryoc = "0.4.0"指定了 dryoc 套件的版本。
Rust 專案管理:相依性管理與功能旗標
Rust 語言本身並不包含亂數產生器,這對於許多程式設計任務至關重要。要使用亂數產生器,你需要使用 rand 套件,它是截至目前為止下載量最高的套件。
相依性管理
在 Rust 中,描述相依性是透過在 Cargo.toml 中列出它們來完成的。一個簡單的例子是使用 rand 套件,如下所示:
[package]
name = "simple-project"
version = "0.1.0"
authors = ["Brenden Matthews <[email protected]>"]
edition = "2018"
[dependencies]
rand = "0.8"
在上述程式碼中,我們包含了 rand 套件,使用該函式庫的最新 0.8 版本。當指定相依性版本時,你應該遵循語義化版本控制(SemVer),它使用 major.minor.patch 模式。預設情況下,Cargo 將使用插入號需求(caret requirements),如果未指定運算元,則允許更新至最不具體的版本。
相依性版本控制
Cargo 支援插入號(^x.y.z)、波浪號(~x.y.z)、萬用字元(*、x.*)、比較需求(>=x、<x.y、=x.y.z)和其組合。下表總結了 SemVer 相依性規範:
| 運算元 | 範例 | 最小版本 | 最大版本 | 是否允許更新? |
|---|---|---|---|---|
| 插入號 | ^2.3.4 | >=2.3.4 | <3.0.0 | 允許 |
| 插入號 | ^2.3 | >=2.3.0 | <3.0.0 | 允許 |
| 波浪號 | ~2.3.4 | >=2.3.4 | <2.4.0 | 允許 |
| 萬用字元 | 2.3.* | >=2.3.0 | <2.4.0 | 允許 |
| 比較 | =2.3.4 | =2.3.4 | =2.3.4 | 不允許 |
處理 Cargo.lock 檔案
處理 Cargo.lock 需要一些特殊考慮,至少在版本控制系統方面是如此。該檔案包含套件相依性(直接和間接相依性)的清單、它們的版本和校驗和,以驗證完整性。
對於函式庫,建議不要將此檔案納入版本控制系統。當使用 Git 時,可以透過將 Cargo.lock 新增至 .gitignore 來實作這一點。省略鎖設定檔案允許下游套件根據需要更新間接相依性。
對於應用程式,建議始終將 Cargo.lock 與 Cargo.toml 一起納入版本控制。這有助於確保已發布版本的行為一致,以防第三方函式庫在未來發生變化。
功能旗標
在發布軟體(尤其是函式庫)時,擁有可選相依性是很常見的做法。這通常是為了保持編譯時間短和二進位制檔案小,並提供效能改進,但會在編譯時增加一些複雜性。
在某些情況下,你可能希望將可選相依性納入你的套件中。這些可以透過 Cargo 的功能旗標來表達。下表顯示了來自 dryoc 套件的功能旗標範例:
| 旗標名稱 | 描述 | 預設啟用? |
|---|---|---|
| serde | 啟用可選的 serde 相依性 | 否 |
| base64 | 啟用 base64 相依性,但僅在 serde 也啟用時啟用 | 否 |
| simd_backend | 為 curve25519-dalek 和 sha2 套件啟用 SIMD 和組譯功能 | 否 |
功能旗標的使用使得套件能夠根據需要包含或排除特定的功能,從而提供更大的彈性和可自定義性。
使用功能旗標的最佳實踐
建議不要過度依賴功能旗標。如果發現自己傾向於建立具有許多功能旗標的超級套件,可能需要考慮將套件分解為更小、獨立的子套件。這種模式相當常見;一些優秀的範例包括 serde、rand 和 rocket 套件。