Rust 測試與文件
單元:文件註解(///、//!)
簡介
在 Rust 生態系統中,文件註解是產生高品質 API 文件的核心工具。透過 ///(行內文件註解)與 //!(模組層級文件註解),開發者可以直接在程式碼中撰寫說明、範例、甚至測試,讓 cargo doc 自動產出完整、易讀的 HTML 文件。良好的文件不只提升程式碼可讀性,也讓團隊協作更順暢,對外部使用者而言,更是降低學習門檻的關鍵。
本篇文章將從 概念、實作範例、常見陷阱、最佳實踐,到 實務應用,一步步帶你掌握 Rust 的文件註解寫法,讓你的程式庫在 Rust 官方文件 中光彩照人。
核心概念
1. /// – 行內文件註解
/// 放在 項目(function、struct、enum、trait…)的前一行,會被 rustdoc 解析為該項目的說明文字。它支援 Markdown 語法,且可以加入 程式碼範例,這些範例會在 cargo test 時自動執行(稱為 doctest)。
範例 1:簡單的函式說明
/// 計算兩個整數的和。
///
/// # 範例
/// ```
/// let sum = add(2, 3);
/// assert_eq!(sum, 5);
/// ```
///
/// 這個函式接受兩個 `i32`,回傳它們的相加結果。
pub fn add(a: i32, b: i32) -> i32 {
a + b
}
重點:
///必須緊貼在項目前,且每行都以///開頭。# 範例(或# Examples)是慣用的標題,方便rustdoc產生目錄。- 程式碼區塊使用三個反引號 ```,並在開頭標註語言
rust,讓語法高亮正確。
2. //! – 模組層級文件註解
//! 用於 檔案或模組的最前面,說明整個模組的目的、使用方式或設計哲學。它同樣支援 Markdown,且常與 mod、crate 的根檔案(lib.rs、main.rs)結合,提供套件的總體說明。
範例 2:crate 根文件的說明
//! # my_crate
//!
//! `my_crate` 提供簡易的數學運算工具,包含加、減、乘、除等函式。
//!
//! ## 使用方式
//! ```rust
//! use my_crate::math::{add, sub};
//!
//! let a = add(10, 5);
//! let b = sub(10, 5);
//! assert_eq!(a, 15);
//! assert_eq!(b, 5);
//! ```
//!
//! 更多細節請參考各模組的文件。
提示:
//!常放在檔案最上方,不要與程式碼混在同一行,否則會被視為普通註解而不會出現在文件中。
3. Markdown 與 rustdoc 的結合
rustdoc 會把文件註解中的 Markdown 直接轉成 HTML。以下是常用的 Markdown 標記:
| Markdown | 產生的效果 |
|---|---|
# 標題 |
<h1> |
## 標題 |
<h2> |
`code` |
行內程式碼 |
rust<br>...<br> |
程式碼區塊,支援語法高亮 |
> 引言 |
引用區塊 |
- 列表 |
無序清單 |
1. 列表 |
有序清單 |
**粗體**、*斜體* |
文字強調 |
4. Doctest – 文件中的測試
只要在文件註解裡寫上可編譯的程式碼區塊,cargo test 會自動把它當作測試執行。這讓文件與測試同步,文件永遠不會過時。
範例 3:失敗的 Doctest
/// 取得字串的長度。
///
/// # 範例
/// ```
/// let len = str_len("hello");
/// // 這裡故意寫錯,測試會失敗,提醒開發者文件與實作不符。
/// assert_eq!(len, 10);
/// ```
pub fn str_len(s: &str) -> usize {
s.len()
}
執行 cargo test 時會得到:
---- str_len::str_len (line 4) stdout ----
thread 'str_len::str_len (line 4)' panicked at 'assertion failed: `(left == right)`
left: `5`,
right: `10`', src/lib.rs:9:5
教訓:Doctest 能即時捕捉文件與程式碼的偏差,務必保持範例正確。
5. 文件註解的可見範圍
| 註解類型 | 作用範圍 | 常見使用位置 |
|---|---|---|
/// |
針對緊鄰的項目(function、struct、enum、trait) | 函式、結構體、列舉等 |
//! |
整個檔案或模組(module) | lib.rs、main.rs、子模組檔案 |
常見陷阱與最佳實踐
1. 註解位置錯誤
- 陷阱:把
///寫在項目之後,或在//!前插入其他程式碼,會導致rustdoc無法辨識。 - 最佳實踐:始終將
///放在項目 前一行,//!放在檔案 最上方。
2. Doctest 沒有 rust 標籤
- 陷阱:使用 ``` 而未指定語言,
rustdoc仍會執行測試,但語法高亮會失效。 - 最佳實踐:在程式碼區塊開頭寫上
rust,確保高亮與測試正確。
3. 文件過於冗長或缺乏範例
- 陷阱:只寫一兩句說明,或把所有細節塞在同一段落,讀者難以快速掌握。
- 最佳實踐:分段說明:概述 → 參數說明 → 回傳值 → 範例 → 錯誤處理。使用 Markdown 標題 (
##,###) 讓文件結構清晰。
4. 使用 pub(crate) 或 pub(super) 時忘記文件
- 陷阱:私有或僅在 crate 內可見的項目若缺少文件,
cargo doc --open仍會顯示「未註解」警告。 - 最佳實踐:即使是私有項目,也建議加上簡短說明,尤其是公共 API 的實作細節。
5. 文件與程式碼脫節
- 陷阱:隨著功能變更,忘記同步更新文件,導致使用者閱讀過時資訊。
- 最佳實踐:將 文件更新 列入 Pull Request 的必備檢查項目,或使用 CI 工具(如
cargo test --doc)確保 Doctest 通過。
實際應用場景
1. 開源套件的 API 文件
在 crates.io 上發布套件時,完整且正確的文件是吸引用戶的第一關卡。使用 /// 為每個公開函式、結構體提供說明與範例,讓使用者在 cargo doc --open 時即可看到即時可執行的範例。
2. 內部企業庫的自動化文件
企業內部的共用庫往往缺乏正式文件,導致新加入的開發者必須閱讀原始碼才能了解使用方式。透過 //! 為模組寫上概覽說明,配合 /// 的細部說明與 Doctest,可自動產出 內部維基 或 HTML 手冊,減少知識傳遞成本。
3. 教學範例與測試的雙重角色
在教學文章或部落格中,常會直接貼上 /// 範例。讀者可以把這段程式碼貼回自己的專案,或直接在 Playground 上執行。因為 Doctest 已經驗證過,範例不會因為版本升級而失效。
4. 產生自訂文件(如 PDF、Markdown)
rustdoc 支援 --output-format json,開發者可以把產出的 JSON 轉換成其他格式(如 PDF、GitBook)。只要文件寫得完整,轉換過程就不會遺失資訊。
總結
///用於 項目層級 的說明,支援 Markdown 與 Doctest,讓 API 文件與測試同步。//!用於 模組或檔案層級 的概覽,提供整體說明與使用指南。- 正確的 位置、語言標籤、範例,是產出高品質文件的關鍵。
- Doctest 不僅是測試工具,也是防止文件過時的最佳防線。
- 在開源、企業內部或教學情境中,善用文件註解可以大幅提升可讀性、可維護性與使用者體驗。
掌握了這兩種註解的寫法與最佳實踐,你的 Rust 專案將不再是「黑盒」程式碼,而是 自說自明、即插即用 的高品質函式庫。現在就把這些技巧應用到你的下一個 crate,讓文件成為你的最佳代碼夥伴吧!