重要觀念
萬般皆對(duì)象乒裆,所有對(duì)象都是繼承自O(shè)bject類碗誉。不要求所有代碼都必須定義在class中
Dart是強(qiáng)類型語(yǔ)言死讹,但也支持類型推斷瞒滴。
支持泛型。
支持頂級(jí)函數(shù)(如main()),也支持函數(shù)的嵌套赞警。
支持頂級(jí)變量妓忍。
不支持
public
,protected
, 和private
關(guān)鍵字,如果以下劃線(_)開頭定義愧旦,則為私有世剖。所有的定義支持字母或下劃線開頭,后面緊跟字母笤虫、下劃線或數(shù)字旁瘫。
包括expressions(條件表達(dá)式,擁有運(yùn)行時(shí)的值琼蚯,如condition ? expr1 : expr2)和statements(聲明表達(dá)式酬凳,不擁有運(yùn)行時(shí)的值,如if-else)遭庶,statements經(jīng)常包含一致多個(gè)expressions宁仔,而expressions不能直接包含statements。
Dart tools 只匯報(bào)兩種類型的問題: warnings 和errors罚拟, Warnings 只提示代碼可能不工作台诗,但不會(huì)阻止程序的執(zhí)行完箩,Errors發(fā)生在編譯或者運(yùn)行期,編譯期的錯(cuò)誤會(huì)中斷代碼執(zhí)行拉队,運(yùn)行期的錯(cuò)誤會(huì)導(dǎo)致程序運(yùn)行發(fā)生異常弊知。
類型聲明規(guī)則
- 不能明確類型的地方需要顯示聲明類型,如方法的參數(shù)粱快、返回值
install(id, destination) => ...//bad
Future<bool> install(PackageId id, String destination) => ...//good
- 避免在本地變量初始化的時(shí)候聲明類型秩彤,
var desserts = <List<Ingredient>>[];//good
List<List<Ingredient>> desserts = <List<Ingredient>>[];//bad
List<AstNode> parameters;//good 未能推斷出類型,需要明確類型
- 避免在函數(shù)表達(dá)式上注釋推斷的參數(shù)類型事哭。
var names = people.map((person) => person.name);//good
var names = people.map((Person person) => person.name);//bad
- 避免在泛型調(diào)用上使用冗余類型參數(shù)漫雷。
Set<String> things = Set();//good
Set<String> things = Set<String>();//bad
var things = Set<String>();//good
var things = Set();//bad
- 如果推斷的類型不正確,需要聲明類型
// good
num highScore(List<num> scores) {
num highest = 0;
for (var score in scores) {
if (score > highest) highest = score;
}
return highest;
}
/** bad
當(dāng)scores包含double類型時(shí)鳍咱,如[1.2]降盹,當(dāng)賦值給highest是會(huì)發(fā)生異常,因?yàn)閔ighest是num類型谤辜,而非num類型
**/
num highScore(List<num> scores) {
var highest = 0;
for (var score in scores) {
if (score > highest) highest = score;
}
return highest;
}
- 更喜歡用動(dòng)態(tài)注釋而不是讓推理失敗蓄坏。
Dart在類型推斷失敗的情況下,會(huì)默認(rèn)為dynamic類型丑念,如果dynamic類型是你真正想要的涡戳,那么最好在聲明時(shí)賦予
dynamic mergeJson(dynamic original, dynamic changes) => ...//good
mergeJson(original, changes) => ...//bad
- 首選函數(shù)類型批注中的簽名。
bool isValid(String value, bool Function(String) test) => ...//good
bool isValid(String value, Function test) => ...//bad
//good
void handleError(void Function() operation, Function errorHandler) {
try {
operation();
} catch (err, stack) {
if (errorHandler is Function(Object)) {
errorHandler(err);
} else if (errorHandler is Function(Object, StackTrace)) {
errorHandler(err, stack);
} else {
throw ArgumentError("errorHandler has wrong signature.");
}
}
}
- 不要為setter指定返回類型脯倚。
void set foo(Foo value) { ... }//bad
set foo(Foo value) { ... }//good
- 不要使用舊的typedef語(yǔ)法渔彰。
//舊,bad
typedef int Comparison<T>(T a, T b);
typedef bool TestNumber(num);
//新推正,good
typedef Comparison<T> = int Function(T, T);
typedef Comparison<T> = int Function(T a, T b);
- 首選內(nèi)聯(lián)函數(shù)類型而不是typedef恍涂。
class FilteredObservable {
final bool Function(Event) _predicate;
final List<void Function(Event)> _observers;
FilteredObservable(this._predicate, this._observers);
void Function(Event) notify(Event event) {
if (!_predicate(event)) return null;
void Function(Event) last;
for (var observer in _observers) {
observer(event);
last = observer;
}
return last;
}
}
- 考慮對(duì)參數(shù)使用函數(shù)類型語(yǔ)法。
Iterable<T> where(bool Function(T) predicate) => ...
- 使用Object而不是dynamic進(jìn)行注釋植榕,以指示允許使用任何對(duì)象乳丰。
使用dynamic會(huì)發(fā)送更復(fù)雜的信號(hào)。這可能意味著DART的類型系統(tǒng)不夠復(fù)雜内贮,無法表示所允許的一組類型产园,或者值來自互操作或靜態(tài)類型系統(tǒng)的權(quán)限之外,或者您明確希望在程序中的該點(diǎn)具有運(yùn)行時(shí)動(dòng)態(tài)性夜郁。
void log(Object object) {
print(object.toString());
}
/// Returns a Boolean representation for [arg], which must
/// be a String or bool.
bool convertToBool(dynamic arg) {
if (arg is bool) return arg;
if (arg is String) return arg == 'true';
throw ArgumentError('Cannot convert $arg to a bool.');
}
- 將Future<void>用作不生成值的異步成員的返回類型什燕。
- 避免使用FutureOr<T>作為返回類型。
如果一個(gè)方法接收FutureOr<int>作為參數(shù)竞端,意味著使用時(shí)可以傳參為int或Future<int>屎即。所以如果你的返回類型FutureOr<int>,則使用方還需要判斷是int還是Future<int>
Future<int> triple(FutureOr<int> value) async => (await value) * 3;//good
//bad
FutureOr<int> triple(FutureOr<int> value) {
if (value is int) return value * 3;
return (value as Future<int>).then((v) => v * 3);
}
//good
Stream<S> asyncMap<T, S>(
Iterable<T> iterable, FutureOr<S> Function(T) callback) async* {
for (var element in iterable) {
yield await callback(element);
}
}
參數(shù)聲明規(guī)則
- 避免定位布爾參數(shù)。
//bad
new Task(true);
new Task(false);
new ListBox(false, true, true);
new Button(false);
//good,考慮使用命名的參數(shù)技俐,增加構(gòu)造函數(shù)乘陪,或使用常量
Task.oneShot();
Task.repeating();
ListBox(scroll: true, showScrollbars: true);
Button(ButtonState.enabled);
//good
listBox.canScroll = true;
button.isEnabled = false;
- 如果用戶可能希望省略前面的參數(shù),請(qǐng)避免使用可選的位置參數(shù)雕擂。
String.fromCharCodes(Iterable<int> charCodes, [int start = 0, int end]);
DateTime(int year,
[int month = 1,
int day = 1,
int hour = 0,
int minute = 0,
int second = 0,
int millisecond = 0,
int microsecond = 0]);
Duration(
{int days = 0,
int hours = 0,
int minutes = 0,
int seconds = 0,
int milliseconds = 0,
int microseconds = 0});
- 避免使用接受特殊“無參數(shù)”值的強(qiáng)制參數(shù)啡邑。
var rest = string.substring(start);//good
var rest = string.substring(start, null);//bad
- 使用inclusive start和exclusive end參數(shù)接受范圍。
[0, 1, 2, 3].sublist(1, 3) // [1, 2]
'abcd'.substring(1, 3) // 'bc'
Equality
- DO override hashCode if you override ==.
- 一定要使==運(yùn)算符遵守相應(yīng)的數(shù)學(xué)規(guī)則井赌。
Reflexive: a == a should always return true.
Symmetric: a == b should return the same thing as b == a.
Transitive: If a == b and b == c both return true, then a == c should too.
- 避免為可變類定義自定義相等谤逼。
- 不要在custom的==運(yùn)算符中檢查空值。
The language specifies that this check is done automatically and your == method is called only if the right-hand side is not null.
//good
class Person {
final String name;
// ···
bool operator ==(other) => other is Person && name == other.name;
int get hashCode => name.hashCode;
}
//bad
class Person {
final String name;
// ···
bool operator ==(other) => other != null && ...
}