[TOC]
>譯者注:對于代碼規范來說每個語言都有自己的代碼規范,很多語言都有通用的代碼規范,而Dart也有自己的語言風格約束。本部分翻譯難度非常大,有很多難懂的表述,原意翻譯加意譯,翻譯不好忘諒解。僅供參考
好的代碼中一個非常重要的部分是好的風格。一致的命名、排版和格式化有助于代碼看起來相同。它利用了我們大多數人的視覺系統中強大的模式匹配硬件。如果我們在整個Dart生態系統中使用一致的樣式,那么我們所有人都可以更容易地學習和貢獻彼此的代碼。
## 標識符
標識符有三種類型。
* 大駝峰法:每個單詞的首字母大寫,包括第一個單詞
* 小駝峰法:除了首個單詞外每個單詞的首字母大寫
* 小寫加下滑下:全部用小寫字母,即使是首字母縮寫也需要用下劃線分割
### 大駝峰命名法
類、枚舉、typedef和類型參數應該大寫每個單詞的第一個字母(包括第一個單詞),并且不使用分隔符。
~~~
class SliderMenu { ... }
class HttpRequest { ... }
typedef Predicate = bool Function<T>(T value);
~~~
甚至包括用于元數據注釋的類。
~~~
class Foo {
const Foo([arg]);
}
@Foo(anArg)
class A { ... }
@Foo()
class B { ... }
~~~
如果注釋類的構造函數不接受參數,那么您可能需要為它創建一個單獨的小寫字符常數。
~~~
const foo = Foo();
@foo
class C { ... }
~~~
### 使用小寫加下劃線來命名庫和源文件
有些文件系統不區分大小寫,所以許多項目要求文件名都是小寫的。使用分隔符可以使名稱在那種形式下仍然可讀。使用下劃線作為分隔符,可以確保名稱仍然是有效的Dart標識符,如果后面的語言支持符號導入,這可能會有幫助。
~~~
library peg_parser.source_scanner;
import 'file_system.dart';
import 'slider_menu.dart';
~~~
以下是非常不推薦的寫法:
~~~
library pegparser.SourceScanner;
import 'file-system.dart';
import 'SliderMenu.dart';
~~~
>注意:如果您選擇命名一個庫,這個指南將指定如何命名它。如果您愿意,可以在文件中省略庫指令。
>
### 使用小寫加下劃線來命名導入前綴。
~~~
import 'dart:math' as math;
import 'package:angular_components/angular_components'
as angular_components;
import 'package:js/js.dart' as js;
~~~
以下寫法不可取:
~~~
import 'dart:math' as Math;
import 'package:angular_components/angular_components'
as angularComponents;
import 'package:js/js.dart' as JS;
~~~
### 使用小駝峰法命名其他標識符。
類成員、頂級定義、變量、參數和命名參數應該大寫每個單詞的第一個字母(第一個單詞除外),并且不使用分隔符。
~~~
var item;
HttpRequest httpRequest;
void align(bool clearItems) {
// ...
}
~~~
### 優先使用小駝峰法作為常量命名。
在新代碼中,對常量變量(包括enum值)使用小駝峰命名法。在使用SCREAMING_CAPS的現有代碼中,您可以繼續使用所有的caps來保持一致。
~~~
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');
class Dice {
static final numberGenerator = Random();
}
~~~
不推薦的做法:
~~~
const PI = 3.14;
const DefaultTimeout = 1000;
final URL_SCHEME = RegExp('^([a-z]+):');
class Dice {
static final NUMBER_GENERATOR = Random();
}
~~~
>注意:我們最初對常量使用了Java的SCREAMING_CAPS樣式。后來作出了改變,因為:
SCREAMING_CAPS在很多情況下都很糟糕,特別是CSS顏色之類的enum值。
常量經常被更改為最終的非常量變量,這就需要更改名稱。
在枚舉類型上自動定義的值屬性是const和小寫的。
### 大寫縮寫和縮寫長于兩個字母就像單詞那樣
大寫的首字母縮略詞很難讀懂,而多個相鄰的首字母縮略詞可能導致名稱不明確。例如,給定一個以HTTPSFTP開頭的名稱,無法判斷它是指HTTPS FTP還是HTTP SFTP。
為了避免這種情況,縮略語和縮略語都像普通的詞一樣大寫,除了兩個字母的縮略語。(像ID和Mr這樣的兩個字母縮寫仍然像單詞一樣大寫)。
~~~
HttpConnectionInfo
uiHandler
IOStream
HttpRequest
Id
DB
~~~
不推薦的做法:
~~~
HTTPConnection
UiHandler
IoStream
HTTPRequest
ID
Db
~~~
### 不使用前綴字母
[匈牙利表示法](https://en.wikipedia.org/wiki/Hungarian_notation)和其他方案出現在BCPL時代,那時編譯器沒有做什么來幫助您理解代碼。因為Dart可以告訴您聲明的類型、范圍、可變性和其他屬性,所以沒有理由將這些屬性編碼為標識符名稱。
~~~
defaultTimeout
~~~
不推薦的做法:
~~~
kDefaultTimeout
~~~
## 排序
為了使你的文件前言保持整潔,我們有規定的命令,指示應該出現在其中。每個“部分”應該用空行分隔。
### 在其他引入之前引入所需的dart庫
~~~
import 'dart:async';
import 'dart:html';
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
~~~
### 在相對引入之前先引入在包中的庫
~~~
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'util.dart';
~~~
### 第三方包的導入先于其他包
如果您有多個“包”,您可以將您自己的包與其他第三方包一起導入,然后將您的包放在一個單獨的部分中。
~~~
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'package:my_package/util.dart';
~~~
### 在所有導入之后,請在單獨的部分中指定導出
~~~
import 'src/error.dart';
import 'src/foo_bar.dart';
export 'src/error.dart';
~~~
不能有以下寫法:
~~~
import 'src/error.dart';
export 'src/error.dart';
import 'src/foo_bar.dart';
~~~
### 按字母順序排序塊
~~~
import 'package:bar/bar.dart';
import 'package:foo/foo.dart';
import 'foo.dart';
import 'foo/foo.dart';
~~~
不推薦的做法:
~~~
import 'package:foo/foo.dart';
import 'package:bar/bar.dart';
import 'foo/foo.dart';
import 'foo.dart';
~~~
## 格式化
與許多語言一樣,Dart忽略了空格。然而,程序開發時沒有。具有一致的空格樣式有助于確保程序開發者看到代碼的方式與編譯器相同。
### 使用dartfmt格式化代碼。
格式化是一項冗長的工作,在重構過程中尤其耗時。幸運的是,你不必為此擔心。我們提供一個復雜的自動代碼格式器,叫做dartfmt,它可以為您實現這一點。我們有一些關于它適用的規則的文檔,但是dartfmt的空格處理規則是Dart的產物。
其余的格式指導方針是針對一些dartfmt不能為您解決的問題。
### 考慮更改代碼,使其成為格式友好的代碼
格式化程序可以用您向它拋出的任何代碼做最好的事情,但是它不能創造奇跡。如果您的代碼有特別長的標識符、深度嵌套的表達式、各種不同類型的操作符等,那么格式化的輸出可能仍然難以讀取。
當這種情況發生時,重新組織或簡化代碼。考慮縮短局部變量名或將表達式提升為新的局部變量。換句話說,對代碼進行同樣的修改,就像手工格式化代碼并使其更具可讀性一樣。把達特fmt看作是一種伙伴關系,您可以在其中一起工作,有時是迭代地,以生成漂亮的代碼。
### 避免單行超過80個字符
可讀性研究表明,長行文本更難閱讀,因為當你移動到下一行的開頭時,你的眼睛必須移動得更遠。這就是為什么報紙和雜志使用多列文本。
如果您真的想要一行超過80個字符,那么我們的經驗是,您的代碼可能太過冗長,而且可能更緊湊一些。主要的違法者通常是[VeryLongCamelCaseClassNames]。問問你自己,“在那個類型的名字中,每個單詞都能告訴我一些關鍵的東西,或者阻止名字的沖突嗎?”如果沒有,考慮省略它。
注意,dartfmt為你做了99%,但最后的1%是你。它不會將長字符串文本拆分為80列,因此您必須手動執行。
我們對uri和文件路徑進行異常處理。當它們出現在注釋或字符串中(通常出現在導入和導出中)時,即使超過了行限制,它們也可能保持在一行上。這使得搜索給定路徑的源文件更加容易。
### 對于所有流控制結構,請使用大括號
這樣做可以避免懸浮的else問題
~~~
if (isWeekDay) {
print('Bike to work!');
} else {
print('Go dancing or read a book!');
}
~~~
這里有一個例外:一個if語句沒有else子句,其中整個if語句和then主體都適合一行。在這種情況下,如果你喜歡的話,你可以去掉大括號:
~~~
if (arg == null) return defaultValue;
~~~
如果流程體超出了一行需要分劃請使用大括號:
~~~
if (overflowChars != other.overflowChars) {
return overflowChars < other.overflowChars;
}
~~~
不推薦的做法:
~~~
if (overflowChars != other.overflowChars)
return overflowChars < other.overflowChars;
~~~