Effective Dart:文件
- 註解
- 文件註解
- 務必使用 /// 文件註解來為成員和類型撰寫文件
- 偏好為公用 API 撰寫文件註解
- 考慮撰寫函式庫層級的文件註解
- 考慮為私有 API 撰寫文件註解
- 務必以單一句子摘要開始文件註解
- 務必將文件註解的第一個句子分成自己的段落
- 避免與周圍的上下文重複
- 偏好以第三人稱動詞開始函式或方法註解
- 偏好以名詞片語開始非布林變數或屬性註解
- 偏好以「是否」開頭,後接名詞或動名詞片語來開始布林變數或屬性註解
- 請勿為屬性的 getter 和 setter 撰寫文件
- 偏好以名詞片語開始函式庫或類型註解
- 考慮在文件註解中加入程式碼範例
- 務必在文件註解中使用方括號來參照範圍內的識別碼
- 務必使用文字來說明參數、傳回值和例外狀況
- 務必將文件註解放在中繼資料註解之前
- Markdown
- 寫作
今天很容易認為您的程式碼很明顯,而沒有意識到您有多依賴腦海中已有的上下文。 剛接觸您程式碼的人,甚至是健忘的未來的您,都不會有這種上下文。 簡潔、準確的註解只需幾秒鐘即可寫完,但可以節省其中一個人幾個小時的時間。
我們都知道程式碼應該自我說明,並非所有註解都有幫助。 但現實情況是,我們大多數人寫的註解都不夠多。 這就像運動:您在技術上可以做太多,但更有可能的是您做得太少。 嘗試加強它。
註解
#以下提示適用於您不希望包含在產生之文件中的註解。
務必像句子一樣格式化註解
#// Not if anything comes before it.
if (_chunks.isNotEmpty) return false;
除非它是區分大小寫的識別碼,否則請將第一個單字大寫。 以句點 (或「!」或「?」,我想是這樣) 結尾。 這適用於所有註解:文件註解、內嵌內容,甚至是 TODO。 即使它是句子片段。
請勿使用區塊註解來撰寫文件
#void greet(String name) {
// Assume we have a valid name.
print('Hi, $name!');
}
void greet(String name) {
/* Assume we have a valid name. */
print('Hi, $name!');
}
您可以使用區塊註解 (/* ... */
) 來暫時註解掉一部分程式碼,但所有其他註解都應該使用 //
。
文件註解
#文件註解特別方便,因為 dart doc
會剖析它們,並從中產生精美的文件頁面。 文件註解是出現在宣告之前,並使用 dart doc
尋找的特殊 ///
語法的任何註解。
務必使用 ///
文件註解來為成員和類型撰寫文件
#Linter 規則:slash_for_doc_comments
使用文件註解而不是一般註解,可以讓 dart doc
找到它並產生其文件。
/// The number of characters in this chunk when unsplit.
int get length => ...
// The number of characters in this chunk when unsplit.
int get length => ...
由於歷史原因,dart doc
支援兩種文件註解的語法:///
(「C# 樣式」)和 /** ... */
(「JavaDoc 樣式」)。 我們偏好 ///
,因為它更精簡。 /**
和 */
會在多行文件註解中加入兩個沒有內容的行。 在某些情況下,///
語法也更容易閱讀,例如,當文件註解包含使用 *
來標記清單項目的項目符號清單時。
如果您偶然發現仍然使用 JavaDoc 樣式的程式碼,請考慮清理它。
偏好為公用 API 撰寫文件註解
#Linter 規則:public_member_api_docs
您不必為每個函式庫、頂層變數、類型和成員撰寫文件,但您應該為它們的大部分撰寫文件。
考慮撰寫函式庫層級的文件註解
#與 Java 等語言不同,在 Dart 中,類別是程式組織的唯一單元,而函式庫本身是用戶直接使用、匯入和思考的實體。 這使得 library
指令成為撰寫文件的絕佳位置,該文件向讀者介紹其中提供的主要概念和功能。 請考慮加入
- 函式庫用途的單一句子摘要。
- 在整個函式庫中使用的術語解釋。
- 幾個完整的程式碼範例,逐步說明如何使用 API。
- 指向最重要或最常用類別和函式的連結。
- 指向函式庫所關注領域的外部參考的連結。
若要為函式庫撰寫文件,請將文件註解放在 library
指令之前,以及任何可能附加在檔案開頭的註解之前。
/// A really great test library.
@TestOn('browser')
library;
考慮為私有 API 撰寫文件註解
#文件註解不僅適用於您函式庫公用 API 的外部消費者。 它們對於理解從函式庫其他部分呼叫的私有成員也很有幫助。
務必以單一句子摘要開始文件註解
#以簡短、以使用者為中心的描述開始您的文件註解,並以句點結尾。 句子片段通常就足夠了。 提供足夠的上下文讓讀者瞭解情況,並決定他們是否應該繼續閱讀或在其他地方尋找問題的解決方案。
/// Deletes the file at [path] from the file system.
void delete(String path) {
...
}
/// Depending on the state of the file system and the user's permissions,
/// certain operations may or may not be possible. If there is no file at
/// [path] or it can't be accessed, this function throws either [IOError]
/// or [PermissionError], respectively. Otherwise, this deletes the file.
void delete(String path) {
...
}
務必將文件註解的第一個句子分成自己的段落
#在第一個句子之後加入空白行,將其分成自己的段落。 如果多個句子的解釋很有用,請將其餘部分放在後面的段落中。
這有助於您撰寫簡潔的第一個句子來摘要文件。 此外,dart doc
等工具會將第一個段落用作類別和成員清單等位置中的簡短摘要。
/// Deletes the file at [path].
///
/// Throws an [IOError] if the file could not be found. Throws a
/// [PermissionError] if the file is present but could not be deleted.
void delete(String path) {
...
}
/// Deletes the file at [path]. Throws an [IOError] if the file could not
/// be found. Throws a [PermissionError] if the file is present but could
/// not be deleted.
void delete(String path) {
...
}
避免與周圍的上下文重複
#類別的文件註解讀者可以清楚地看到類別的名稱、它實作的介面等等。 在閱讀成員的文件時,簽章就在那裡,而且封閉類別也很明顯。 無需在文件註解中將所有內容都拼出來。 相反地,請專注於解釋讀者不知道的內容。
class RadioButtonWidget extends Widget {
/// Sets the tooltip to [lines], which should have been word wrapped using
/// the current font.
void tooltip(List<String> lines) {
...
}
}
class RadioButtonWidget extends Widget {
/// Sets the tooltip for this radio button widget to the list of strings in
/// [lines].
void tooltip(List<String> lines) {
...
}
}
如果您確實沒有任何有趣的話可說,而且無法從宣告本身推斷出來,請省略文件註解。 與其浪費讀者的時間告訴他們已經知道的事情,不如什麼都不說。
偏好以第三人稱動詞開始函式或方法註解
#文件註解應專注於程式碼執行什麼。
/// Returns `true` if every element satisfies the [predicate].
bool all(bool predicate(T element)) => ...
/// Starts the stopwatch if not already running.
void start() {
...
}
偏好以名詞片語開始非布林變數或屬性註解
#文件註解應強調屬性是什麼。 即使對於可能執行計算或其他工作的 getter 也是如此。 呼叫者關心的是該工作的結果,而不是工作本身。
/// The current day of the week, where `0` is Sunday.
int weekday;
/// The number of checked buttons on the page.
int get checkedCount => ...
偏好以「是否」開頭,後接名詞或動名詞片語來開始布林變數或屬性註解
#文件註解應說明此變數代表的狀態。 即使對於可能執行計算或其他工作的 getter 也是如此。 呼叫者關心的是該工作的結果,而不是工作本身。
/// Whether the modal is currently displayed to the user.
bool isVisible;
/// Whether the modal should confirm the user's intent on navigation.
bool get shouldConfirm => ...
/// Whether resizing the current browser window will also resize the modal.
bool get canResize => ...
請勿為屬性的 getter 和 setter 撰寫文件
#如果一個屬性同時具有 getter 和 setter,則只需要為其中一個建立文件註解。dart doc
會將 getter 和 setter 視為單一欄位,如果 getter 和 setter 都有文件註解,則 dart doc
會捨棄 setter 的文件註解。
/// The pH level of the water in the pool.
///
/// Ranges from 0-14, representing acidic to basic, with 7 being neutral.
int get phLevel => ...
set phLevel(int level) => ...
/// The depth of the water in the pool, in meters.
int get waterDepth => ...
/// Updates the water depth to a total of [meters] in height.
set waterDepth(int meters) => ...
偏好以名詞片語開始函式庫或類型註解
#類別的文件註解通常是程式中最重要的文件。它們描述類型的恆定條件、建立其使用的術語,並為類別成員的其他文件註解提供上下文。在這裡多花一點功夫可以使其他成員更容易記錄。
/// A chunk of non-breaking output text terminated by a hard or soft newline.
///
/// ...
class Chunk { ... }
考慮在文件註解中加入程式碼範例
#/// Returns the lesser of two numbers.
///
/// ```dart
/// min(5, 3) == 3
/// ```
num min(num a, num b) => ...
人類很擅長從範例中歸納,因此即使只有一個程式碼範例,也能使 API 更容易學習。
務必在文件註解中使用方括號來參照範圍內的識別碼
#Linter 規則:comment_references
如果將變數、方法或類型名稱等內容放在方括號中,則 dart doc
會查找該名稱並連結到相關的 API 文件。括號是可選的,但可以更清楚地表明您指的是方法還是建構子。
/// Throws a [StateError] if ...
/// similar to [anotherMethod()], but ...
若要連結到特定類別的成員,請使用類別名稱和成員名稱,並用點號分隔。
/// Similar to [Duration.inDays], but handles fractional days.
點號語法也可以用來指稱具名的建構子。對於未命名的建構子,請在類別名稱後使用 .new
。
/// To create a point, call [Point.new] or use [Point.polar] to ...
務必使用文字來說明參數、傳回值和例外狀況
#其他語言會使用冗長的標籤和章節來描述方法的參數和回傳值。
/// Defines a flag with the given name and abbreviation.
///
/// @param name The name of the flag.
/// @param abbr The abbreviation for the flag.
/// @returns The new flag.
/// @throws ArgumentError If there is already an option with
/// the given name or abbreviation.
Flag addFlag(String name, String abbr) => ...
Dart 的慣例是將其整合到方法描述中,並使用方括號來突顯參數。
/// Defines a flag.
///
/// Throws an [ArgumentError] if there is already an option named [name] or
/// there is already an option using abbreviation [abbr]. Returns the new flag.
Flag addFlag(String name, String abbr) => ...
務必將文件註解放在中繼資料註解之前
#/// A button that can be flipped on and off.
@Component(selector: 'toggle')
class ToggleComponent {}
@Component(selector: 'toggle')
/// A button that can be flipped on and off.
class ToggleComponent {}
Markdown
#您可以在文件註解中使用大多數的 markdown 格式,而 dart doc
會使用 markdown 套件 對其進行相應的處理。
已經有很多指南介紹 Markdown。它之所以如此普及,正是我們選擇它的原因。這裡只是一個簡單的範例,讓您了解它支援的功能。
/// This is a paragraph of regular text.
///
/// This sentence has *two* _emphasized_ words (italics) and **two**
/// __strong__ ones (bold).
///
/// A blank line creates a separate paragraph. It has some `inline code`
/// delimited using backticks.
///
/// * Unordered lists.
/// * Look like ASCII bullet lists.
/// * You can also use `-` or `+`.
///
/// 1. Numbered lists.
/// 2. Are, well, numbered.
/// 1. But the values don't matter.
///
/// * You can nest lists too.
/// * They must be indented at least 4 spaces.
/// * (Well, 5 including the space after `///`.)
///
/// Code blocks are fenced in triple backticks:
///
/// ```dart
/// this.code
/// .will
/// .retain(its, formatting);
/// ```
///
/// The code language (for syntax highlighting) defaults to Dart. You can
/// specify it by putting the name of the language after the opening backticks:
///
/// ```html
/// <h1>HTML is magical!</h1>
/// ```
///
/// Links can be:
///
/// * https://www.just-a-bare-url.com
/// * [with the URL inline](https://google.com)
/// * [or separated out][ref link]
///
/// [ref link]: https://google.com
///
/// # A Header
///
/// ## A subheader
///
/// ### A subsubheader
///
/// #### If you need this many levels of headers, you're doing it wrong
避免過度使用 markdown
#如果拿不定主意,就減少格式化。格式化的目的是為了闡明您的內容,而不是取代內容。文字才是最重要的。
避免使用 HTML 格式化
#在少數情況下,例如表格,使用格式化可能很有用,但在幾乎所有情況下,如果內容複雜到無法用 Markdown 表達,最好不要表達。
偏好使用反引號圍欄程式碼區塊
#Markdown 有兩種方式來表示程式碼區塊:在每一行程式碼前縮排四個空格,或將其包圍在一對三反引號「fence」行中。當在 Markdown 清單等縮排已具有意義的情況下,或當程式碼區塊本身包含縮排程式碼時,前者語法會較為脆弱。
反引號語法可以避免那些縮排上的問題,讓您可以指出程式碼的語言,並且與使用反引號來表示行內程式碼的方式一致。
/// You can use [CodeBlockExample] like this:
///
/// ```dart
/// var example = CodeBlockExample();
/// print(example.isItGreat); // "Yes."
/// ```
/// You can use [CodeBlockExample] like this:
///
/// var example = CodeBlockExample();
/// print(example.isItGreat); // "Yes."
寫作
#我們認為自己是程式設計師,但原始檔案中的大多數字元主要是為了讓人們閱讀。英文是我們用來修改同事大腦的程式設計語言。如同任何程式語言一樣,值得花費精力來提高您的熟練度。
本節列出了一些關於我們文件編寫的準則。您可以從 技術寫作風格 等文章中了解更多關於技術寫作最佳實務的資訊。
偏好簡潔
#要清晰精確,但也要簡潔。
避免縮寫和首字母縮略詞,除非它們很明顯
#很多人不知道「i.e.」、「e.g.」和「et al.」的意思。您確定您領域中的每個人都知道的縮寫,可能並沒有您想像的那麼廣為人知。
偏好使用「this」而不是「the」來參照成員的實例
#在為類別的成員撰寫文件時,您通常需要回頭參考呼叫該成員的物件。使用「the」可能會造成歧義。
class Box {
/// The value this wraps.
Object? _value;
/// True if this box contains a value.
bool get hasValue => _value != null;
}
除非另有說明,否則本網站上的文件反映的是 Dart 3.6.0。頁面最後更新時間為 2024-12-11。 檢視原始碼 或 回報問題。