Flutter 代碼開發規範文檔 僅作參考 html
標識符三種類型
大駝峯
類、枚舉、typedef和類型參數api
class SliderMenu { ... } class HttpRequest { ... } typedef Predicate = bool Function<T>(T value);
包括用於元數據註釋的類緩存
class Foo { const Foo([arg]); } @Foo(anArg) class A { ... } @Foo() class B { ... }
使用小寫加下劃線來命名庫和源文件
less
library peg_parser.source_scanner; import 'file_system.dart'; import 'slider_menu.dart';
不推薦以下寫法:dom
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;
不推薦以下寫法:async
import 'dart:math' as Math; import 'package:angular_components/angular_components' as angularComponents; import 'package:js/js.dart' as JS;
使用小駝峯法命名其餘標識符
ide
var item; HttpRequest httpRequest; void align(bool clearItems) { // ... }
優先使用小駝峯法做爲常量命名
函數
const pi = 3.14; const defaultTimeout = 1000; final urlScheme = RegExp('^([a-z]+):'); class Dice { static final numberGenerator = Random(); }
不推薦以下寫法:ui
const PI = 3.14; const DefaultTimeout = 1000; final URL_SCHEME = RegExp('^([a-z]+):'); class Dice { static final NUMBER_GENERATOR = Random(); }
不使用前綴字母
由於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';
全部流控制結構,請使用大括號
這樣作能夠避免懸浮的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;
註釋
要像句子同樣格式化
除非是區分大小寫的標識符,不然第一個單詞要大寫。以句號結尾(或「!」或「?」)。對於全部的註釋都是如此:doc註釋、內聯內容,甚至TODOs。即便是一個句子片斷。
greet(name) { // Assume we have a valid name. print('Hi, $name!'); }
不推薦以下寫法:
greet(name) { /* Assume we have a valid name. */ print('Hi, $name!'); }
可使用塊註釋(/…/)臨時註釋掉一段代碼,可是全部其餘註釋都應該使用//
Doc註釋
使用///文檔註釋來記錄成員和類型。
使用doc註釋而不是常規註釋,可讓dartdoc找到並生成文檔。
/// The number of characters in this chunk when unsplit. int get length => ...
考慮爲私有api編寫文檔註釋
Doc註釋並不只僅針對庫的公共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) { ... }
字符串的使用
優先使用模板字符串
'Hello, $name! You are ${year - birth} years old.';
集合
儘量使用集合字面量
若是要建立一個不可增加的列表,或者其餘一些自定義集合類型,那麼不管如何,都要使用構造函數。
var points = []; var addresses = {}; var lines = <Lines>[];
不推薦以下寫法:
var points = List(); var addresses = Map();
不要使用.length查看集合是否爲空
if (lunchBox.isEmpty) return 'so hungry...'; if (words.isNotEmpty) return words.join(' ');
不推薦以下寫法:
if (lunchBox.length == 0) return 'so hungry...'; if (!words.isEmpty) return words.join(' ');
考慮使用高階方法轉換序列
若是有一個集合,而且但願從中生成一個新的修改後的集合,那麼使用.map()、.where()和Iterable上的其餘方便的方法一般更短,也更具備聲明性
var aquaticNames = animals .where((animal) => animal.isAquatic) .map((animal) => animal.name);
避免使用帶有函數字面量的Iterable.forEach()
在Dart中,若是你想遍歷一個序列,慣用的方法是使用循環。
for (var person in people) { ... }
不推薦以下寫法:
people.forEach((person) { ... });
不要使用List.from(),除非打算更改結果的類型
給定一個迭代,有兩種明顯的方法能夠生成包含相同元素的新列表
var copy1 = iterable.toList(); var copy2 = List.from(iterable);
明顯的區別是第一個比較短。重要的區別是第一個保留了原始對象的類型參數
// Creates a List<int>: var iterable = [1, 2, 3]; // Prints "List<int>": print(iterable.toList().runtimeType);
// Creates a List<int>: var iterable = [1, 2, 3]; // Prints "List<dynamic>": print(List.from(iterable).runtimeType);
參數的使用
使用=將命名參數與其默認值分割開
因爲遺留緣由,Dart均容許「:」和「=」做爲指定參數的默認值分隔符。爲了與可選的位置參數保持一致,使用「=」。
void insert(Object item, {int at = 0}) { ... }
不推薦以下寫法:
void insert(Object item, {int at: 0}) { ... }
若是參數是可選的,但沒有給它一個默認值,則語言隱式地使用null做爲默認值,所以不須要編寫它
void error([String message]) { stderr.write(message ?? '\n'); }
不推薦以下寫法:
void error([String message = null]) { stderr.write(message ?? '\n'); }
變量
不要顯式地將變量初始化爲空
在Dart中,未顯式初始化的變量或字段自動被初始化爲null。不要多餘賦值null
int _nextId; class LazyId { int _id; int get id { if (_nextId == null) _nextId = 0; if (_id == null) _id = _nextId++; return _id; } }
不推薦以下寫法:
int _nextId = null; class LazyId { int _id = null; int get id { if (_nextId == null) _nextId = 0; if (_id == null) _id = _nextId++; return _id; } }
避免儲存你能計算的東西
在設計類時,您一般但願將多個視圖公開到相同的底層狀態。一般你會看到在構造函數中計算全部視圖的代碼,而後存儲它們:
class Circle { num radius; num area; num circumference; Circle(num radius) : radius = radius, area = pi * radius * radius, circumference = pi * 2.0 * radius; }
如上代碼問題:
浪費內存 緩存的問題是無效——如何知道什麼時候緩存過時須要從新計算?
推薦的寫法以下:
class Circle { num radius; Circle(this.radius); num get area => pi * radius * radius; num get circumference => pi * 2.0 * radius; }
類成員
不要把沒必要要地將字段包裝在getter和setter中
不推薦以下寫法:
class Box { var _contents; get contents => _contents; set contents(value) { _contents = value; } }
優先使用final字段來建立只讀屬性
尤爲對於 StatelessWidget
在不須要的時候不要用this
不推薦以下寫法:
class Box { var value; void clear() { this.update(null); } void update(value) { this.value = value; } }
推薦以下寫法:
class Box { var value; void clear() { update(null); } void update(value) { this.value = value; } }
構造函數
儘量使用初始化的形式
不推薦以下寫法:
class Point { num x, y; Point(num x, num y) { this.x = x; this.y = y; } }
推薦以下寫法:
class Point { num x, y; Point(this.x, this.y); }
不要使用new
Dart2使new 關鍵字可選
推薦寫法:
Widget build(BuildContext context) { return Row( children: [ RaisedButton( child: Text('Increment'), ), Text('Click!'), ], ); }
不推薦以下寫法:
Widget build(BuildContext context) { return new Row( children: [ new RaisedButton( child: new Text('Increment'), ), new Text('Click!'), ], ); }
異步
優先使用async/await代替原始的futures
async/await語法提升了可讀性,容許你在異步代碼中使用全部Dart控制流結構。
Future<int> countActivePlayers(String teamName) async { try { var team = await downloadTeam(teamName); if (team == null) return 0; var players = await team.roster; return players.where((player) => player.isActive).length; } catch (e) { log.error(e); return 0; } }
當異步沒有任何用處時,不要使用它
若是能夠在不改變函數行爲的狀況下省略異步,那麼就這樣作:
Future afterTwoThings(Future first, Future second) { return Future.wait([first, second]); }
不推薦寫法:
Future afterTwoThings(Future first, Future second) async { return Future.wait([first, second]); }