Cargo、套件與 crates.io(Cargo, crates, and crates.io)
/ Cargo -> KAR-goh; crates.io -> KRAYTS-dot-eye-oh /
要建構任何稍具規模的 C 程式,就得親手擺弄一個建構工具。你寫一份 Makefile,列出哪些檔案編譯成哪些目的檔、以什麼順序、用哪些旗標、又怎麼連結在一起;而當你想用別人的函式庫時,你得去找它的原始碼或一個系統套件、安裝它的標頭檔與函式庫檔、再告訴編譯器和連結器去哪裡找它們。它能用,但建構描述得由你維護、依賴項則是一件手工苦差。Rust 內附一個工具 Cargo,把整件事都做了——它同時是編譯器驅動程式、建構系統、與套件管理員,三合一。
兩個詞撐起這套系統。crate(套件)是 Rust 的編譯與分享單位——大致上就是一個函式庫或一個程式。package(套件包)是一個或多個 crate 的捆束,由一個叫 Cargo.toml 的小檔案描述,它列出套件的名稱、版本,以及最關鍵的——它依照名稱與版本列出的依賴項。cargo build 編譯你的套件;cargo run 建構並執行它;cargo test 跑它的測試;cargo new 開一個正確佈局的新專案。與 Make 的對比在於你不必描述「怎麼建」——Cargo 已經知道慣例(原始碼放 src/、輸出放 target/),並自己算出建構圖與增量建構。你大多只要宣告你依賴什麼。crates.io 是公開的登錄處,社群所發布開源 crate 的共享倉庫;在 Cargo.toml 的 [dependencies] 底下加一行,cargo build 就會下載那個 crate 以及它自己所依賴的一切,編譯它們,再把它們連結進來。
為何重要:依賴管理——在 C 裡是套件管理員、系統路徑與版本不符出了名地痛苦的拼湊——在 Rust 裡是一個宣告式檔案加一道指令。這大大降低了重用程式碼的成本,也確實是 Rust 專案推進得快的部分原因。誠實的提醒和每個套件生態系背負的是同一個:拉進一個 crate 意味著信任並繼承它的程式碼(以及它自己的依賴,可能很多),所以一道輕鬆的 cargo add 不是免費的午餐——每一個依賴項都是更多你現在要出貨、要持續更新、並在正確性與安全性上都得倚賴的程式碼。
# Cargo.toml [package] name = "hello" version = "0.1.0" edition = "2021" [dependencies] rand = "0.8" # 下次建構時從 crates.io 拉下來 # 接著在命令列: # $ cargo run 建構套件並執行它
依名稱與版本宣告一個依賴;Cargo 替你抓取、建構並連結它。
Cargo 用一個宣告式檔案取代了手寫 Makefile 加手動找依賴。但你每加一個 crate,都是你現在要出貨並信任的程式碼——便利並不抹去一棵不斷成長的依賴樹的代價。