高效 Dart
在過去的幾年裡,我們編寫了大量的 Dart 程式碼,並從中學習到了哪些有效,哪些無效。我們與您分享這些經驗,以便您也能編寫出一致、健壯、快速的程式碼。其中有兩個總體主題:
保持一致性。 當涉及到格式和大小寫等問題時,關於哪個更好的爭論是主觀的,無法解決。我們知道的是,保持一致性客觀上是有幫助的。
如果兩段程式碼看起來不同,那應該是因為它們在某種有意義的方式上確實不同。當一段程式碼引人注目時,它應該有一個有用的理由。
簡潔。 Dart 的設計旨在易於上手,因此它繼承了 C、Java、JavaScript 和其他語言的許多相同語句和表示式。但我們建立 Dart 是因為這些語言所提供的功能仍有很大的改進空間。我們添加了許多功能,從字串插值到初始化形式,以幫助您更簡單、更容易地表達您的意圖。
如果有一種以上的方式來表達某件事,您通常應該選擇最簡潔的方式。這並不是說您應該像程式碼高爾夫一樣把整個程式塞進一行。目標是程式碼要經濟,而不是密集。
指南
#我們將這些指南分成幾個獨立的頁面,以便於理解:
風格指南 – 這定義了程式碼佈局和組織的規則,或者至少是
dart format無法為您處理的部分。風格指南還指定了識別符號的格式:camelCase、using_underscores等。文件指南 – 這告訴您有關注釋內容所需的一切知識。包括文件註釋和普通的、一般的程式碼註釋。
用法指南 – 這教您如何最佳地利用語言特性來實現行為。如果它在語句或表示式中,這裡都會涵蓋。
設計指南 – 這是最“軟”的指南,但範圍最廣。它涵蓋了我們所學到的關於為庫設計一致、可用 API 的知識。如果它在型別簽名或宣告中,這裡都會涉及。
有關所有指南的連結,請參閱摘要。
如何閱讀指南
#每個指南都分為幾個部分。每個部分包含一個指南列表。每個指南都以以下單詞之一開頭:
DO(務必) 指南描述了應始終遵循的實踐。幾乎永遠沒有偏離它們的有效理由。
DON'T(切勿) 指南是其反面:幾乎永遠不是好主意的事情。希望我們沒有像其他語言那樣多的這類指南,因為我們歷史包袱較少。
PREFER(優先) 指南是您應該遵循的實踐。但是,在某些情況下,可能需要採取其他做法。只是在您這樣做時,請務必瞭解忽略該指南的全部影響。
AVOID(避免) 指南是“優先”的反面:您不應該做的事情,但極少數情況下可能有充分理由去做。
CONSIDER(考慮) 指南是您可能或可能不希望遵循的實踐,具體取決於情況、先例和您自己的偏好。
有些指南描述了規則不適用的例外情況。列出的例外可能不詳盡——您可能仍需要根據其他情況進行判斷。
這聽起來像是如果您沒有正確繫好鞋帶,警察就會破門而入。情況沒那麼糟。這裡的大多數指南都是常識,我們都是通情達理的人。目標始終是編寫出良好、可讀且可維護的程式碼。
Dart 分析器提供了一個 Linter,可幫助您編寫遵循這些及其他指南的良好、一致的程式碼。如果存在一個或多個可以幫助您遵循指南的linter 規則,則該指南會連結到這些規則。連結使用以下格式:
Linter 規則: unnecessary_getters_setters
要了解如何使用 Linter,請參閱啟用 Linter 規則和Linter 規則列表。
術語表
#為了使指南簡潔,我們使用了一些簡寫術語來指代不同的 Dart 結構。
庫成員是頂層欄位、getter、setter 或函式。基本上,頂層不是型別的所有內容。
類成員是類中宣告的建構函式、欄位、getter、setter、函式或運算子。類成員可以是例項或靜態的,抽象或具體的。
成員是庫成員或類成員。
變數,一般而言,指頂層變數、引數和區域性變數。它不包括靜態或例項欄位。
型別是任何命名型別宣告:類、typedef 或列舉。
屬性是頂層變數、getter(在類中或頂層,例項或靜態)、setter(同上)或欄位(例項或靜態)。大致是指任何“類欄位”的命名構造。
所有規則總結
#風格
#識別符號
- DO (務必) 使用
UpperCamelCase命名型別。 - DO (務必) 使用
UpperCamelCase命名擴充套件。 - DO (務必) 使用
lowercase_with_underscores命名包、目錄和原始檔。 - DO (務必) 使用
lowercase_with_underscores命名匯入字首。 - DO (務必) 使用
lowerCamelCase命名其他識別符號。 - PREFER (優先) 為常量名使用
lowerCamelCase。 - DO (務必) 將兩個字母以上的縮寫和首字母縮略詞像單詞一樣大寫。
- PREFER (優先) 對未使用的回撥引數使用萬用字元。
- DON'T (切勿) 對非私有識別符號使用前導下劃線。
- DON'T (切勿) 使用字首字母。
- DON'T (切勿) 顯式命名庫。
排序
- DO (務必) 將
dart:匯入放在其他匯入之前。 - DO (務必) 將
package:匯入放在相對匯入之前。 - DO (務必) 在所有匯入之後,在一個單獨的章節中指定匯出。
- DO (務必) 按字母順序排序各章節。
格式化
文件
#註釋
文件註釋
- DO (務必) 使用
///文件註釋來註釋成員和型別。 - PREFER (優先) 為公共 API 編寫文件註釋。
- CONSIDER (考慮) 編寫庫級別的文件註釋。
- CONSIDER (考慮) 為私有 API 編寫文件註釋。
- DO (務必) 用一個單句摘要開始文件註釋。
- DO (務必) 將文件註釋的第一句話獨立成一個段落。
- AVOID (避免) 與周圍上下文冗餘。
- PREFER (優先) 如果函式的或方法的主要目的是產生副作用,則以第三人稱動詞開頭其註釋。
- PREFER (優先) 非布林變數或屬性註釋以名詞短語開頭。
- PREFER (優先) 布林變數或屬性註釋以“Whether”開頭,後跟名詞或動名詞短語。
- PREFER (優先) 如果返回一個值是函式或方法的主要目的,則使用名詞短語或非祈使動詞短語。
- DON'T (切勿) 為屬性的 getter 和 setter 都編寫文件。
- PREFER (優先) 庫或型別註釋以名詞短語開頭。
- CONSIDER (考慮) 在文件註釋中包含程式碼示例。
- DO (務必) 在文件註釋中使用方括號來引用作用域內的識別符號。
- DO (務必) 使用散文解釋引數、返回值和異常。
- DO (務必) 將文件註釋放在元資料註解之前。
Markdown
編寫
用法
#庫
- DO (務必) 在
part of指令中使用字串。 - DON'T (切勿) 匯入其他包的
src目錄中的庫。 - DON'T (切勿) 允許匯入路徑伸入或伸出
lib目錄。 - PREFER (優先) 使用相對匯入路徑。
空值
- DON'T (切勿) 顯式地將變數初始化為
null。 - DON'T (切勿) 使用顯式的預設值
null。 - DON'T (切勿) 在相等操作中使用
true或false。 - AVOID (避免)
late變數,如果您需要檢查它們是否已初始化。 - CONSIDER (考慮) 使用型別提升或空值檢查模式來使用可空型別。
字串
集合
- DO (務必) 儘可能使用集合字面量。
- DON'T (切勿) 使用
.length來檢查集合是否為空。 - AVOID (避免) 將
Iterable.forEach()與函式字面量一起使用。 - DON'T (切勿) 使用
List.from(),除非您打算更改結果的型別。 - DO (務必) 使用
whereType()按型別過濾集合。 - DON'T (切勿) 在附近操作即可時使用
cast()。 - AVOID (避免) 使用
cast()。
函式
變數
成員
- DON'T (切勿) 不必要地將欄位包裝在 getter 和 setter 中。
- PREFER (優先) 使用
final欄位來建立只讀屬性。 - CONSIDER (考慮) 對簡單成員使用
=>。 - DON'T (切勿) 使用
this.,除非是重定向到命名建構函式或避免遮蔽。 - DO (務必) 儘可能在宣告時初始化欄位。
建構函式
- DO (務必) 儘可能使用初始化形參。
- DON'T (切勿) 在建構函式初始化列表可以做到時使用
late。 - DO (務必) 對空建構函式體使用
;而不是{}。 - DON'T (切勿) 使用
new。 - DON'T (切勿) 冗餘地使用
const。
錯誤處理
- AVOID (避免) 沒有
on子句的 catch。 - DON'T (切勿) 丟棄沒有
on子句的 catch 中的錯誤。 - DO (務必) 僅針對程式錯誤丟擲實現
Error的物件。 - DON'T (切勿) 顯式捕獲
Error或實現它的型別。 - DO (務必) 使用
rethrow重新丟擲捕獲的異常。
非同步
設計
#名稱
- DO (務必) 一致地使用術語。
- AVOID (避免) 縮寫。
- PREFER (優先) 將最具描述性的名詞放在最後。
- CONSIDER (考慮) 讓程式碼讀起來像句子。
- PREFER (優先) 對非布林屬性或變數使用名詞短語。
- PREFER (優先) 對布林屬性或變數使用非祈使動詞短語。
- CONSIDER (考慮) 省略命名布林引數的動詞。
- PREFER (優先) 為布林屬性或變數使用“肯定”名稱。
- PREFER (優先) 對主要目的是產生副作用的函式或方法使用祈使動詞短語。
- PREFER (優先) 如果返回一個值是函式或方法的主要目的,則使用名詞短語或非祈使動詞短語。
- CONSIDER (考慮) 如果您想突出其執行的工作,則為函式或方法使用祈使動詞短語。
- AVOID (避免) 以
get開頭方法名。 - PREFER (優先) 如果方法將物件的狀態複製到一個新物件,則將其命名為
to___()。 - PREFER (優先) 如果方法返回由原始物件支援的不同表示,則將其命名為
as___()。 - AVOID (避免) 在函式或方法的名稱中描述引數。
- DO (務必) 在命名型別引數時遵循現有助記符約定。
庫
類和 Mixin
- AVOID (避免) 在簡單的函式可以做到時定義一個只有一個成員的抽象類。
- AVOID (避免) 定義一個只包含靜態成員的類。
- AVOID (避免) 擴充套件一個不打算被子類化的類。
- DO (務必) 使用類修飾符來控制您的類是否可以被擴充套件。
- AVOID (避免) 實現一個不打算作為介面的類。
- DO (務必) 使用類修飾符來控制您的類是否可以作為介面。
- PREFER (優先) 定義純
mixin或純class而不是mixin class。
建構函式
成員
- PREFER (優先) 將欄位和頂層變數設為
final。 - DO (務必) 對概念上訪問屬性的操作使用 getter。
- DO (務必) 對概念上改變屬性的操作使用 setter。
- DON'T (切勿) 定義沒有對應 getter 的 setter。
- AVOID (避免) 使用執行時型別測試來偽造過載。
- AVOID (避免) 沒有初始化的公共
late final欄位。 - AVOID (避免) 返回可空的
Future,Stream和集合型別。 - AVOID (避免) 為了實現鏈式呼叫而從方法返回
this。
型別
- DO (務必) 為沒有初始化的變數新增型別註解。
- DO (務必) 如果型別不明顯,則為欄位和頂層變數新增型別註解。
- DON'T (切勿) 冗餘地為已初始化的區域性變數新增型別註解。
- DO (務必) 在函式宣告上註解返回型別。
- DO (務必) 在函式宣告上註解引數型別。
- DON'T (切勿) 在函式表示式上註解推斷的引數型別。
- DON'T (切勿) 為初始化形參新增型別註解。
- DO (務必) 為未推斷出的泛型呼叫編寫型別引數。
- DON'T (切勿) 為已推斷出的泛型呼叫編寫型別引數。
- AVOID (避免) 編寫不完整的泛型型別。
- DO (務必) 使用
dynamic進行註解,而不是讓推斷失敗。 - PREFER (優先) 函式型別註解中的簽名。
- DON'T (切勿) 為 setter 指定返回型別。
- DON'T (切勿) 使用舊式的 typedef 語法。
- PREFER (優先) 行內函式型別而非 typedefs。
- PREFER (優先) 對引數使用函式型別語法。
- AVOID (避免) 使用
dynamic,除非您想停用靜態檢查。 - DO (務必) 使用
Future<void>作為不產生值的非同步成員的返回型別。 - AVOID (避免) 使用
FutureOr<T>作為返回型別。
引數
- AVOID (避免) 位置布林引數。
- AVOID (避免) 可選位置引數,如果使用者可能想省略前面的引數。
- AVOID (避免) 接受特殊“無引數”值的強制引數。
- DO (務必) 使用包含起始和排他結束引數來接受一個範圍。
相等性