一個(gè)簡(jiǎn)單的 Dart 程序
// 定義一個(gè)函數(shù)雕憔。
printInteger(int aNumber) {
print('The number is $aNumber.'); // 打印輸出到控制臺(tái)姿骏。
}
// Dart 程序從 main() 函數(shù)開始執(zhí)行。
main() {
var number = 42; // 聲明并初始化一個(gè)變量斤彼。
printInteger(number); // 調(diào)用一個(gè)函數(shù)分瘦。
}
// This is a comment.
// 注釋。
以雙斜杠開頭的一行語(yǔ)句稱為單行注釋琉苇。Dart 同樣支持多行注釋和文檔注釋嘲玫。
int
表示一種數(shù)據(jù)類型。Dart 中一些其他的內(nèi)置類型包括 String
并扇、List
和 bool
去团。
42
表示一個(gè)數(shù)字字面量。數(shù)字字面量是一種編譯時(shí)常量穷蛹。
print()
一種便利的將信息輸出顯示的方式土陪。
'...' (或 "...")
表示字符串字面量。
{expression})
表示字符串插值:字符串字面量中包含的變量或表達(dá)式肴熏。
main()
一個(gè)特殊且 必須的 頂級(jí)函數(shù)鬼雀,Dart 應(yīng)用程序總是會(huì)從該函數(shù)開始執(zhí)行。
var
用于定義變量蛙吏,通過這種方式定義變量不需要指定變量類型源哩。
重要概念
在學(xué)習(xí) Dart 語(yǔ)言時(shí), 應(yīng)該牢記以下幾點(diǎn):
- 所有變量引用的都是 對(duì)象,每個(gè)對(duì)象都是一個(gè) 類 的實(shí)例出刷。數(shù)字璧疗、函數(shù)以及
null
都是對(duì)象。所有的類都繼承于 Object 類馁龟。
盡管 Dart 是強(qiáng)類型語(yǔ)言崩侠,但是在聲明變量時(shí)指定類型是可選的,因?yàn)?Dart 可以進(jìn)行類型推斷坷檩。在上述代碼中却音,變量
number
的類型被推斷為int
類型。如果想顯式地聲明一個(gè)不確定的類型矢炼,可以使用特殊類型dynamic
系瓢。Dart 支持泛型,比如
List<int>
(表示一組由 int 對(duì)象組成的列表)或List<dynamic>
(表示一組由任何類型對(duì)象組成的列表)句灌。Dart 支持頂級(jí)函數(shù)(例如
main
方法)夷陋,同時(shí)還支持定義屬于類或?qū)ο蟮暮瘮?shù)(即 靜態(tài) 和 實(shí)例方法)欠拾。你還可以在函數(shù)中定義函數(shù)(嵌套 或 局部函數(shù))。Dart 支持頂級(jí) 變量骗绕,以及定義屬于類或?qū)ο蟮淖兞浚o態(tài)和實(shí)例變量)藐窄。實(shí)例變量有時(shí)稱之為域或?qū)傩浴?/p>
Dart 沒有類似于 Java 那樣的
public
、protected
和private
成員訪問限定符酬土。如果一個(gè)標(biāo)識(shí)符以下劃線 (_) 開頭則表示該標(biāo)識(shí)符在庫(kù)內(nèi)是私有的荆忍。可以查閱 庫(kù)和可見性 獲取更多相關(guān)信息撤缴。標(biāo)識(shí)符 可以以字母或者下劃線 (_) 開頭刹枉,其后可跟字符和數(shù)字的組合。
Dart 中 表達(dá)式 和 語(yǔ)句 是有區(qū)別的屈呕,表達(dá)式有值而語(yǔ)句沒有微宝。比如條件表達(dá)式
expression condition ? expr1 : expr2
中含有值expr1
或expr2
。與 if-else 分支語(yǔ)句相比虎眨,if-else
分支語(yǔ)句則沒有值芥吟。一個(gè)語(yǔ)句通常包含一個(gè)或多個(gè)表達(dá)式,但是一個(gè)表達(dá)式不能只包含一個(gè)語(yǔ)句专甩。Dart 工具可以顯示 警告 和 錯(cuò)誤 兩種類型的問題。警告表明代碼可能有問題但不會(huì)阻止其運(yùn)行钉稍。錯(cuò)誤分為編譯時(shí)錯(cuò)誤和運(yùn)行時(shí)錯(cuò)誤涤躲;編譯時(shí)錯(cuò)誤代碼無法運(yùn)行;運(yùn)行時(shí)錯(cuò)誤會(huì)在代碼運(yùn)行時(shí)導(dǎo)致異常贡未。
變量
下面的示例代碼將創(chuàng)建一個(gè)變量并將其初始化:
var name = 'Bob';
變量?jī)H存儲(chǔ)對(duì)象的引用种樱。這里名為 name
的變量存儲(chǔ)了一個(gè) String
類型對(duì)象的引用,“Bob” 則是該對(duì)象的值俊卤。
name
變量的類型被推斷為 String
嫩挤,但是你可以為其指定類型。如果一個(gè)對(duì)象的引用不局限于單一的類型消恍,可以根據(jù)設(shè)計(jì)指南將其指定為 Object
或 dynamic
類型岂昭。
dynamic name = 'Bob';
除此之外你也可以指定類型:
String name = 'Bob';
默認(rèn)值
在 Dart 中,未初始化的變量擁有一個(gè)默認(rèn)的初始化值: null狠怨。即便數(shù)字也是如此约啊,因?yàn)樵?Dart 中一切皆為對(duì)象,數(shù)字也不例外佣赖。
int lineCount;
assert(lineCount == null);
Final 和 Const
如果你不想更改一個(gè)變量恰矩,可以使用關(guān)鍵字 final 或者 const 修飾變量,這兩個(gè)關(guān)鍵字可以替代 var 關(guān)鍵字或者加在一個(gè)具體的類型前憎蛤。一個(gè) final 變量只可以被賦值一次外傅;一個(gè) const 變量是一個(gè)編譯時(shí)常量(const 變量同時(shí)也是 final 的)。頂層的 final 變量或者類的 final 變量在其第一次使用的時(shí)候被初始化。
下面的示例中我們創(chuàng)建并設(shè)置兩個(gè) final 變量:
final name = 'Bob'; // 此時(shí) final 替代 var 用于修飾變量名
final String nickname = 'Bobby';// 將 final 加在具體的類型前
你不能修改一個(gè) final 變量的值:
name = 'Alice'; // 錯(cuò)誤:final 變量只能被設(shè)置一次萎胰。
使用關(guān)鍵字 const 修飾變量表示該變量為 編譯時(shí)常量碾盟。如果使用 const 修飾類中的變量,則必須加上 static 關(guān)鍵字奥洼,即 static const(注意:順序不能顛倒(譯者注))巷疼。在聲明 const 變量時(shí)可以直接為其賦值,也可以使用其它的 const 變量為其賦值:
const bar = 1000000; // 直接賦值
const double atm = 1.01325 * bar; // 利用其它 const 變量賦值
const 關(guān)鍵字不僅僅可以用來定義常量灵奖,還可以用來創(chuàng)建 常量值嚼沿,該常量值可以賦予給任何變量。你也可以將構(gòu)造函數(shù)聲明為 const 的瓷患,這種類型的構(gòu)造函數(shù)創(chuàng)建的對(duì)象是不可改變的骡尽。
var foo = const [];
final bar = const [];
const baz = []; // 相當(dāng)于 `const []`
如果使用初始化表達(dá)式為常量賦值可以省略掉關(guān)鍵字 const
,比如上面的常量 baz
的賦值就省略掉了 const
擅编。
沒有使用 final 或 const 修飾的變量的值是可以被更改的攀细,即使這些變量之前引用過 const 的值。
foo = [1, 2, 3]; // foo 的值之前為 const []
常量的值不可以被修改:
baz = [42]; // 錯(cuò)誤:常量不可以被賦值爱态。
內(nèi)置類型
Dart 語(yǔ)言支持下列的類型:
numbers
strings
booleans
lists (也被稱為 arrays)
sets
maps
runes (用于在字符串中表示 Unicode 字符)
symbols
可以直接使用字面量來初始化上述類型谭贪。例如 'This is a string'
是一個(gè)字符串字面量,true
是一個(gè)布爾字面量锦担。
由于 Dart 中每個(gè)變量引用都指向一個(gè)對(duì)象(一個(gè) 類 的實(shí)例)俭识,你通常也可以使用 構(gòu)造器 來初始化變量。一些內(nèi)置的類型有它們自己的構(gòu)造器洞渔。例如你可以使用 Map()
來創(chuàng)建一個(gè) map 對(duì)象套媚。
Numbers
Dart 支持兩種 Number 類型
int
整數(shù)值長(zhǎng)度不超過64位具體取值范圍依賴于不同的平臺(tái)。在 DartVM 上其取值位于 -263 至 263 - 1 之間磁椒。編譯成 JavaScript 的 Dart 使用 JavaScript 數(shù)字堤瘤,其允許的取值范圍在 -253 至 253 - 1 之間。
double
64位的雙精度浮點(diǎn)數(shù)字浆熔,且符合 IEEE 754 標(biāo)準(zhǔn)本辐。
int
和 double
都是 num
的子類。num 中定義了一些基本的運(yùn)算符比如 +医增、-师郑、*、/ 等调窍,還定義了 abs()
宝冕、ceil()
和 floor()
等方法(位運(yùn)算符,比如 ? 定義在 int 中)邓萨。如果 num 及其子類不滿足你的要求地梨,可以查看 dart:math 庫(kù)中的 API菊卷。
整數(shù)是不帶小數(shù)點(diǎn)的數(shù)字。下面是一些定義整數(shù)字面量的例子:
var x = 1;
var hex = 0xDEADBEEF;
如果一個(gè)數(shù)字包含了小數(shù)點(diǎn)宝剖,那么它就是浮點(diǎn)型的洁闰。下面是一些定義浮點(diǎn)數(shù)字面量的例子:
var y = 1.1;
var exponents = 1.42e5;
從 Dart 2.1 開始,整型字面量將會(huì)在必要的時(shí)候自動(dòng)轉(zhuǎn)換成浮點(diǎn)數(shù)字面量:
double z = 1; // 相當(dāng)于 double z = 1.0.
下面是字符串和數(shù)字之間轉(zhuǎn)換的方式:
// String -> int
var one = int.parse('1');
assert(one == 1);
// String -> double
var onePointOne = double.parse('1.1');
assert(onePointOne == 1.1);
// int -> String
String oneAsString = 1.toString();
assert(oneAsString == '1');
// double -> String
String piAsString = 3.14159.toStringAsFixed(2);
assert(piAsString == '3.14');
整型支持傳統(tǒng)的位移操作万细,比如移位(<<扑眉、>>)、按位與(&)赖钞、按位或( )腰素,例如:
assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111
數(shù)字字面量為編譯時(shí)常量。很多算術(shù)表達(dá)式只要其操作數(shù)是常量雪营,則表達(dá)式結(jié)果也是編譯時(shí)常量弓千。
const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;
Strings
Dart 字符串是 UTF-16 編碼的字符序列∠灼穑可以使用單引號(hào)或者雙引號(hào)來創(chuàng)建字符串:
var s1 = '使用單引號(hào)創(chuàng)建字符串字面量洋访。';
var s2 = "雙引號(hào)也可以用于創(chuàng)建字符串字面量。";
var s3 = '使用單引號(hào)創(chuàng)建字符串時(shí)可以使用斜杠來轉(zhuǎn)義那些與單引號(hào)沖突的字符串:\'谴餐。';
var s4 = "而在雙引號(hào)中則不需要使用轉(zhuǎn)義與單引號(hào)沖突的字符串:'";
可以在字符串中以 ${表達(dá)式} 的形式使用表達(dá)式姻政,如果表達(dá)式是一個(gè)標(biāo)識(shí)符,可以省略掉 {}岂嗓。如果表達(dá)式的結(jié)果為一個(gè)對(duì)象扶歪,則 Dart 會(huì)調(diào)用該對(duì)象的 toString 方法來獲取一個(gè)字符串。
var s = '字符串插值';
assert('Dart 有$s摄闸,使用起來非常方便。' == 'Dart 有字符串插值妹萨,使用起來非常方便年枕。');
assert('使用${s.substring(3,5)}表達(dá)式也非常方便' == '使用插值表達(dá)式也非常方便。');
可以使用 + 運(yùn)算符將兩個(gè)字符串連接為一個(gè)乎完,也可以將多個(gè)字符串挨著放一起變?yōu)橐粋€(gè):
var s1 = '可以拼接'
'字符串'
"即便它們不在同一行熏兄。";
assert(s1 == '可以拼接字符串即便它們不在同一行。');
var s2 = '使用加號(hào) + 運(yùn)算符' + '也可以達(dá)到相同的效果树姨。';
assert(s2 == '使用加號(hào) + 運(yùn)算符也可以達(dá)到相同的效果摩桶。');
可以使用三個(gè)單引號(hào)或者三個(gè)雙引號(hào)創(chuàng)建多行字符串:
var s1 = '''
你可以像這樣創(chuàng)建多行字符串。
''';
var s2 = """這也是一個(gè)多行字符串帽揪。""";
在字符串前加上 r 作為前綴創(chuàng)建 “raw” 字符串(即不會(huì)被做任何處理(比如轉(zhuǎn)義)的字符串):
var s = r'在 raw 字符串中硝清,轉(zhuǎn)義字符串 \n 會(huì)直接輸出 “\n” 而不是轉(zhuǎn)義為換行。';
字符串字面量是一個(gè)編譯時(shí)常量转晰,只要是編譯時(shí)常量都可以作為字符串字面量的插值表達(dá)式:
// 可以將下面三個(gè)常量作為字符串插值拼接到字符串字面量中芦拿。
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';
// 而下面三個(gè)常量則不能作為字符串插值拼接到字符串字面量士飒。
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];
const validConstString = '$aConstNum $aConstBool $aConstString';
// const invalidConstString = '$aNum $aBool $aString $aConstList';
Booleans
Dart 使用 bool 關(guān)鍵字表示布爾類型,布爾類型只有兩個(gè)對(duì)象 true 和 false蔗崎,兩者都是編譯時(shí)常量酵幕。
Dart 的類型安全不允許你使用類似 if (nonbooleanValue) 或者 assert (nonbooleanValue) 這樣的代碼檢查布爾值。相反缓苛,你應(yīng)該總是顯示地檢查布爾值芳撒,比如像下面的代碼這樣:
// 檢查是否為空字符串。
var fullName = '';
assert(fullName.isEmpty);
// 檢查是否小于等于零未桥。
var hitPoints = 0;
assert(hitPoints <= 0);
// 檢查是否為 null笔刹。
var unicorn;
assert(unicorn == null);
// 檢查是否為 NaN。
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);
Lists
數(shù)組 Array 是幾乎所有編程語(yǔ)言中最常見的集合類型钢属,在 Dart 中數(shù)組由 List 對(duì)象表示徘熔。通常稱之為 List。
Dart 中 List 字面量看起來與 JavaScript 中數(shù)組字面量一樣淆党。下面是一個(gè) Dart List 的示例:\
var list = [1, 2, 3];
List 的下標(biāo)索引從 0 開始酷师,第一個(gè)元素的下標(biāo)為 0,最后一個(gè)元素的下標(biāo)為 list.length - 1染乌。你可以像 JavaScript 中的用法那樣獲取 Dart 中 List 的長(zhǎng)度以及元素:
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
如果想要?jiǎng)?chuàng)建一個(gè)編譯時(shí)常量的 List山孔,在 List 字面量前添加 const 關(guān)鍵字即可:
var constantList = const [1, 2, 3];
// constantList[1] = 1; // 取消注釋將導(dǎo)致出錯(cuò)。
Dart 在 2.3 引入了 擴(kuò)展操作符(...)和 null-aware 擴(kuò)展操作符(...?)荷憋,它們提供了一種將多個(gè)元素插入集合的簡(jiǎn)潔方法台颠。
例如,你可以使用擴(kuò)展操作符(...)將一個(gè) List 中的所有元素插入到另一個(gè) List 中:
var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);
如果擴(kuò)展操作符右邊可能為 null 勒庄,你可以使用 null-aware 擴(kuò)展操作符(...?)來避免產(chǎn)生異常:
var list;
var list2 = [0, ...?list];
assert(list2.length == 1);
Dart 在 2.3 還同時(shí)引入了 Collection If 和 Collection For串前,在構(gòu)建集合時(shí),可以使用條件判斷(if)和循環(huán)(for)实蔽。
下面示例是使用 Collection If 來創(chuàng)建一個(gè) List 的示例荡碾,它可能包含 3 個(gè)或 4 個(gè)元素:
var nav = [
'Home',
'Furniture',
'Plants',
if (promoActive) 'Outlet'
];
下面示例是使用 Collection For 將列表中的元素修改后添加到另一個(gè)列表中的示例:
var listOfInts = [1, 2, 3];
var listOfStrings = [
'#0',
for (var i in listOfInts) '#$i'
];
assert(listOfStrings[1] == '#1');
List 類中有許多用于操作 List 的便捷方法,你可以查閱泛型和集合獲取更多與之相關(guān)的信息局装。
Sets
Dart 中使用 Set 來表示無序且元素唯一的集合坛吁,Dart 支持 Set 字面量以及 Set 類型兩種形式的 Set。
下面是使用 Set 字面量來創(chuàng)建一個(gè) Set 集合的方法:
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Dart 推斷
halogens變量是一個(gè)
Set<String>類型的集合铐尚,如果往該 Set 中添加類型不正確的對(duì)象則會(huì)報(bào)錯(cuò)拨脉。你可以查閱類型推斷獲取更多與之相關(guān)的內(nèi)容。
可以使用在 {} 前加上類型參數(shù)的方式創(chuàng)建一個(gè)空的 Set宣增,或者將 {} 賦值給一個(gè) Set 類型的變量:
var names = <String>{};// 類型+{}的形式創(chuàng)建Set玫膀。
// Set<String> names = {}; // 聲明類型變量的形式創(chuàng)建 Set。
// var names = {}; // 這樣的形式將創(chuàng)建一個(gè) Map 而不是 Set爹脾。
Map 字面量語(yǔ)法同 Set 字面量語(yǔ)法非常相似匆骗。因?yàn)橄扔械?Map 字面量語(yǔ)法劳景,所以 {} 默認(rèn)是 Map 類型。如果忘記在 {} 上注釋類型或賦值到一個(gè)未聲明類型的變量上碉就,那么 Dart 會(huì)創(chuàng)建一個(gè)類型為 Map<dynamic, dynamic> 的對(duì)象盟广。
向一個(gè)已存在的 Set 中添加項(xiàng)目可以使用 add() 方法或 addAll() 方法:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
使用 .length 可以獲取 Set 中元素的數(shù)量:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);
可以在 Set 字面量前添加 const 關(guān)鍵字創(chuàng)建一個(gè) Set 編譯時(shí)常量:
final constantSet = const {
'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
};
// constantSet.add('helium'); // 取消注釋將導(dǎo)致出錯(cuò)。
從 Dart 2.3 開始瓮钥,Set 可以像 List 一樣支持使用擴(kuò)展操作符(...
和 ...?
)以及 Collection If 和 Collection For 操作筋量。你可以查閱 List 擴(kuò)展操作符和List 集合操作符獲取更多相關(guān)信息。
Maps
通常來說碉熄, Map 是用來關(guān)聯(lián) keys 和 values 的對(duì)象桨武。 keys 和 values 可以是任何類型的對(duì)象。在一個(gè) Map 對(duì)象中一個(gè) key 只能出現(xiàn)一次锈津。但是 value 可以出現(xiàn)多次呀酸。 Dart 中 Map 通過 Map 字面量和 Map 類型來實(shí)現(xiàn)。通常來說琼梆,Map 是一個(gè)鍵值對(duì)相關(guān)的對(duì)象性誉。其中鍵和值都可以是任何類型的對(duì)象错览。每個(gè) 鍵 只能出現(xiàn)一次但是 值 可以重復(fù)出現(xiàn)多次。Dart 中 Map 提供了 Map 字面量以及 Map 類型兩種形式的 Map。
下面是一對(duì)使用 Map 字面量創(chuàng)建 Map 的例子:
var gifts = {
// 鍵: 值
'first': 'partridge',
'second': 'turtledoves',
'fifth': 'golden rings'
};
var nobleGases = {
2: 'helium',
10: 'neon',
18: 'argon',
};
- Dart 將
gifts
變量的類型推斷為Map<String, String>
,而降nobleGases
的類型推斷為Map<int, String>
癌幕。如果你向這兩個(gè) Map 對(duì)象中添加不正確的類型值,將導(dǎo)致運(yùn)行時(shí)異常厅瞎。你可以閱讀類型推斷獲取更多相關(guān)信息。
你也可以使用 Map 的構(gòu)造器創(chuàng)建 Map:
var gifts = Map();
gifts['first'] = 'partridge';
gifts['second'] = 'turtledoves';
gifts['fifth'] = 'golden rings';
var nobleGases = Map();
nobleGases[2] = 'helium';
nobleGases[10] = 'neon';
nobleGases[18] = 'argon';
- 這里為什么使用
Map()
而不是使用new Map()
構(gòu)造 Map 對(duì)象。因?yàn)閺?Dart2 開始,構(gòu)造對(duì)象的new
關(guān)鍵字可以被省略掉畔勤。你可以查閱構(gòu)造函數(shù)的使用獲取更多相關(guān)信息。
向現(xiàn)有的 Map 中添加鍵值對(duì)與 JavaScript 的操作類似:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // 添加鍵值對(duì)
從一個(gè) Map 中獲取一個(gè)值的操作也與 JavaScript 類似。
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');
如果檢索的 Key 不存在于 Map 中則會(huì)返回一個(gè) null:
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
使用 .length 可以獲取 Map 中鍵值對(duì)的數(shù)量:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
在一個(gè) Map 字面量前添加 const 關(guān)鍵字可以創(chuàng)建一個(gè) Map 編譯時(shí)常量:
final constantMap = const {
2: 'helium',
10: 'neon',
18: 'argon',
};
// constantMap[2] = 'Helium'; // 取消注釋將導(dǎo)致出錯(cuò)。
從 Dart 2.3 Map 可以像 List 一樣支持使用擴(kuò)展操作符(...
和 ...?
)以及 Collection If 和 Collection For 操作。你可以查閱 List 擴(kuò)展操作符和 List 集合操作符獲取更多相關(guān)信息。
Runes
Dart 使用 Runes 符文來表示 UTF-32 編碼的字符串。
Unicode 編碼為每一個(gè)字母竣付、數(shù)字和符號(hào)都定義了一個(gè)唯一的數(shù)值筛璧。因?yàn)?Dart 中的字符串是一個(gè) UTF-16 的字符序列巫糙,所以如果想要表示 32 位的 Unicode 數(shù)值則需要一種特殊的語(yǔ)法疲牵。
通常使用 \uXXXX
來表示 Unicode 字符,XXXX 是一個(gè)四位數(shù)的 16 進(jìn)制數(shù)字。例如心形字符(?)的 Unicode 為 \u2665
。對(duì)于不是四位數(shù)的 16 進(jìn)制數(shù)字,需要使用大括號(hào)將其括起來。例如大笑的 emoji 表情(??)的 Unicode 為 \u{1f600}
徒溪。
String 類中有一些屬性可以用來提取字符串的 Rune 符文信息。codeUnitAt
和 codeUnit
屬性返回 16 位代碼單元高氮。runes
屬性可以獲取字符串的 Runes 符文。
Symbols
Symbol 表示 Dart 中聲明的操作符或者標(biāo)識(shí)符,該類型的對(duì)象幾乎不會(huì)被使用到峡继,但是如果需要按名稱引用它們的 API 時(shí)就非常有用。因?yàn)榇a壓縮后會(huì)改變這些符號(hào)的名稱但不會(huì)改變具體的符號(hào)。
可以使用在標(biāo)識(shí)符前加 # 前綴來獲取 Symbol:
#radix
#bar
Symbol 字面量是編譯時(shí)常量踊赠。
Functions
Dart 是一種真正面向?qū)ο蟮恼Z(yǔ)言伦籍,所以即便函數(shù)也是對(duì)象并且類型為 Function作儿,這意味著函數(shù)可以被賦值給變量或者作為其它函數(shù)的參數(shù)。你也可以像調(diào)用函數(shù)一樣調(diào)用 Dart 類的實(shí)例机断。詳情請(qǐng)查閱 可調(diào)用的類奋蔚。
下面是定義一個(gè)函數(shù)的例子:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
雖然高效 Dart 指南建議在公開的 API 上定義返回類型晋涣,不過即便不定義佃扼,該函數(shù)也依然有效:
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
如果函數(shù)體內(nèi)只包含一個(gè)表達(dá)式匠题,你可以使用簡(jiǎn)寫語(yǔ)法:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
語(yǔ)法 => 表達(dá)式 是 { return 表達(dá)式; } 的簡(jiǎn)寫梦裂,=> 有時(shí)也稱之為胖箭頭語(yǔ)法牵咙。
函數(shù)可以有兩種形式的參數(shù):必要參數(shù) 和 可選參數(shù)窟却。必要參數(shù)定義在參數(shù)列表前面昼丑,可選參數(shù)則定義在必要參數(shù)后面】浜眨可選參數(shù)可以是 命名的 或 位置的菩帝。
可選參數(shù)
可選參數(shù)分為命名參數(shù)和位置參數(shù),可在參數(shù)列表中任選其一使用茬腿,但兩者不能同時(shí)出現(xiàn)在參數(shù)列表中呼奢。
命名參數(shù)
當(dāng)你調(diào)用函數(shù)時(shí),可以使用 參數(shù)名: 參數(shù)值 的形式來指定命名參數(shù)切平。例如:
enableFlags(bold: true, hidden: false);
定義函數(shù)時(shí)握础,使用 {param1, param2, …} 來指定命名參數(shù):
/// 設(shè)置 [bold] 和 [hidden] 標(biāo)識(shí)……
void enableFlags({bool bold, bool hidden}) {...}
雖然命名參數(shù)是可選參數(shù)的一種類型,但是你仍然可以使用 @required 注解來標(biāo)識(shí)一個(gè)命名參數(shù)是必須的參數(shù)悴品,此時(shí)調(diào)用者則必須為該參數(shù)提供一個(gè)值禀综。例如:
const Scrollbar({Key key, @required Widget child})
如果調(diào)用者想要通過 Scrollbar
的構(gòu)造函數(shù)構(gòu)造一個(gè) Scrollbar 對(duì)象而不提供 child
參數(shù),則會(huì)導(dǎo)致編譯錯(cuò)誤苔严。
@required 注解定義在 meta 包中定枷,可以直接導(dǎo)入 package:meta/meta.dart
包使用。
位置參數(shù)
使用 []
將一系列參數(shù)包裹起來作為位置參數(shù):
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
下面是不使用可選參數(shù)調(diào)用上述函數(shù)的示例:
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
下面是使用可選參數(shù)調(diào)用上述函數(shù)的示例:
assert(say('Bob', 'Howdy', 'smoke signal') ==
'Bob says Howdy with a smoke signal');
默認(rèn)參數(shù)值
可以用 = 為函數(shù)的命名和位置參數(shù)定義默認(rèn)值届氢,默認(rèn)值必須為編譯時(shí)常量依鸥,沒有指定默認(rèn)值的情況下默認(rèn)值為 null。
下面是設(shè)置可選參數(shù)默認(rèn)值示例:
/// 設(shè)置 [bold] 和 [hidden] 標(biāo)識(shí)……
void enableFlags({bool bold = false, bool hidden = false}) {...}
// bold 的值將為 true悼沈;而 hidden 將為 false贱迟。
enableFlags(bold: true);
- 在老版本的 Dart 代碼中會(huì)使用冒號(hào)(
:
)而不是=
來設(shè)置命名參數(shù)的默認(rèn)值。原因在于剛開始的時(shí)候命名參數(shù)只支持:
絮供。不過現(xiàn)在這個(gè)支持已經(jīng)過時(shí)衣吠,所以我們建議你現(xiàn)在都 使用=
來指定默認(rèn)值。
String say(String from, String msg,
[String device = 'carrier pigeon', String mood]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
if (mood != null) {
result = '$result (in a $mood mood)';
}
return result;
}
assert(say('Bob', 'Howdy') ==
'Bob says Howdy with a carrier pigeon');
List 或 Map 同樣也可以作為默認(rèn)值壤靶。下面的示例定義了一個(gè)名為 doStuff() 的函數(shù)缚俏,并為其名為 list 和 gifts 的參數(shù)指定了一個(gè) List 類型的值和 Map 類型的值。
void doStuff(
{List<int> list = const [1, 2, 3],
Map<String, String> gifts = const {
'first': 'paper',
'second': 'cotton',
'third': 'leather'
}}) {
print('list: $list');
print('gifts: $gifts');
}
main() 函數(shù)
每個(gè) Dart 程序都必須有一個(gè) main() 頂級(jí)函數(shù)作為程序的入口贮乳,main() 函數(shù)返回值為 void 并且有一個(gè) List<String> 類型的可選參數(shù)忧换。
下面是一個(gè) Web 應(yīng)用的 main() 函數(shù)示例:
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
- 上述代碼中的
..
語(yǔ)法稱之為 級(jí)聯(lián)調(diào)用。使用級(jí)聯(lián)訪問可以在一個(gè)對(duì)象上執(zhí)行多個(gè)操作向拆。
下面是使用命令行訪問帶參數(shù)的 main() 函數(shù)示例:
// 使用命令 dart args.dart 1 test 運(yùn)行該應(yīng)用
void main(List<String> arguments) {
print(arguments);
assert(arguments.length == 2);
assert(int.parse(arguments[0]) == 1);
assert(arguments[1] == 'test');
}
你可以通過使用 參數(shù)庫(kù) 來定義和解析命令行參數(shù)亚茬。
函數(shù)作為一級(jí)對(duì)象
可以將函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)。例如:
void printElement(int element) {
print(element);
}
var list = [1, 2, 3];
// 將 printElement 函數(shù)作為參數(shù)傳遞浓恳。
list.forEach(printElement);
你也可以將函數(shù)賦值給一個(gè)變量刹缝,比如:
var loudify = (msg) => '!!! ${msg.toUpperCase()} !!!';
assert(loudify('hello') == '!!! HELLO !!!');
該示例中使用了匿名函數(shù)碗暗。下一節(jié)會(huì)有更多與其相關(guān)的介紹。
匿名函數(shù)
大多數(shù)方法都是有名字的梢夯,比如 main()
或 printElement()
言疗。你可以創(chuàng)建一個(gè)沒有名字的方法,稱之為 匿名函數(shù)颂砸,或 Lambda表達(dá)式 或 Closure閉包噪奄。你可以將匿名方法賦值給一個(gè)變量然后使用它,比如將該變量添加到集合或從中刪除人乓。
匿名方法看起來與命名方法類似勤篮,在括號(hào)之間可以定義參數(shù),參數(shù)之間用逗號(hào)分割撒蟀。
后面大括號(hào)中的內(nèi)容則為函數(shù)體:
([[*類型*] *參數(shù)*[, …]]) { *函數(shù)體*; };
下面代碼定義了只有一個(gè)參數(shù) item
且沒有參數(shù)類型的匿名方法。List 中的每個(gè)元素都會(huì)調(diào)用這個(gè)函數(shù)温鸽,打印元素位置和值的字符串:
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
詞法作用域
Dart 是詞法有作用域語(yǔ)言保屯,變量的作用域在寫代碼的時(shí)候就確定了,大括號(hào)內(nèi)定義的變量只能在大括號(hào)內(nèi)訪問涤垫,與 Java 類似姑尺。
下面是一個(gè)嵌套函數(shù)中變量在多個(gè)作用域中的示例:
bool topLevel = true;
void main() {
var insideMain = true;
void myFunction() {
var insideFunction = true;
void nestedFunction() {
var insideNestedFunction = true;
assert(topLevel);
assert(insideMain);
assert(insideFunction);
assert(insideNestedFunction);
}
}
}
注意 nestedFunction()
函數(shù)可以訪問包括頂層變量在內(nèi)的所有的變量。
詞法閉包
閉包 即一個(gè)函數(shù)對(duì)象蝠猬,即使函數(shù)對(duì)象的調(diào)用在它原始作用域之外切蟋,依然能夠訪問在它詞法作用域內(nèi)的變量。
函數(shù)可以封閉定義到它作用域內(nèi)的變量榆芦。接下來的示例中柄粹,函數(shù) makeAdder()
捕獲了變量 addBy
。無論函數(shù)在什么時(shí)候返回匆绣,它都可以使用捕獲的 addBy
變量驻右。
/// 返回一個(gè)將 [addBy] 添加到該函數(shù)參數(shù)的函數(shù)。
Function makeAdder(num addBy) {
return (num i) => addBy + i;
}
void main() {
// 生成加 2 的函數(shù)崎淳。
var add2 = makeAdder(2);
// 生成加 4 的函數(shù)堪夭。
var add4 = makeAdder(4);
assert(add2(3) == 5);
assert(add4(3) == 7);
}
測(cè)試函數(shù)是否相等
下面是頂級(jí)函數(shù),靜態(tài)方法和示例方法相等性的測(cè)試示例:
void foo() {} // 定義頂層函數(shù)
class A {
static void bar() {} // 定義靜態(tài)方法
void baz() {} // 定義實(shí)例方法
}
void main() {
var x;
// 比較頂層函數(shù)是否相等拣凹。
x = foo;
assert(foo == x);
// 比較靜態(tài)方法是否相等森爽。
x = A.bar;
assert(A.bar == x);
// 比較實(shí)例方法是否相等。
var v = A(); // A 的實(shí)例 #1
var w = A(); // A 的實(shí)例 #2
var y = w;
x = w.baz;
// 這兩個(gè)閉包引用了相同的實(shí)例對(duì)象嚣镜,因此它們相等爬迟。
assert(y.baz == x);
// 這兩個(gè)閉包引用了不同的實(shí)例對(duì)象,因此它們不相等菊匿。
assert(v.baz != w.baz);
}
返回值
所有的函數(shù)都有返回值雕旨。沒有顯示返回語(yǔ)句的函數(shù)最后一行默認(rèn)為執(zhí)行 return null;扮匠。
foo() {}
assert(foo() == null);
運(yùn)算符
下表是 Dart 中定義的運(yùn)算符,很多運(yùn)算符都可以重寫凡涩。詳情參考重寫運(yùn)算符棒搜。
描述 運(yùn)算符
一元后綴 表達(dá)式++ 表達(dá)式-- () [] . ?.
一元前綴 -表達(dá)式 !表達(dá)式 ~表達(dá)式 ++表達(dá)式 --表達(dá)式
乘除法 * / % ~/
加減法 + -
位運(yùn)算 << >> >>>
二進(jìn)制與 &
二進(jìn)制異或 ^
二進(jìn)制或 |
關(guān)系和類型測(cè)試 >= > <= < as is is!
相等判斷 == !=
邏輯與 &&
邏輯或 ||
空判斷 ??
條件表達(dá)式 表達(dá)式 1 ? 表達(dá)式 2 : 表達(dá)式 3
級(jí)聯(lián) ..
賦值 = *= /= += -= &= ^= 等等……
一旦你使用了運(yùn)算符,就創(chuàng)建了表達(dá)式活箕。下面是一些運(yùn)算符表達(dá)式的示例:
a++
a + b
a = b
a == b
c ? a : b
a is T
在運(yùn)算符表 中力麸,運(yùn)算符的優(yōu)先級(jí)按先后排列,即第一行優(yōu)先級(jí)最高育韩,最后一行優(yōu)先級(jí)最低克蚂,而同一行中,最左邊的優(yōu)先級(jí)最高筋讨,最右邊的優(yōu)先級(jí)最低埃叭。例如:%
運(yùn)算符優(yōu)先級(jí)高于 ==
,而 ==
高于 &&
悉罕。根據(jù)優(yōu)先級(jí)規(guī)則赤屋,那么意味著以下兩行代碼執(zhí)行的效果相同:
// 括號(hào)提高了可讀性。
if ((n % i == 0) && (d % i == 0)) ...
// 難以理解壁袄,但是與上面的代碼效果一樣类早。
if (n % i == 0 && d % i == 0) ...
- 對(duì)于有兩個(gè)操作數(shù)的運(yùn)算符,左邊的操作數(shù)決定了運(yùn)算符的功能嗜逻。比如如果有一個(gè) Vector 對(duì)象和一個(gè) Point 對(duì)象涩僻,表達(dá)式 aVector + aPoint 中所使用的是 Vector 對(duì)象中定義的 + 運(yùn)算符。
算術(shù)運(yùn)算符
Dart 支持常用的算術(shù)運(yùn)算符:
運(yùn)算符 描述
- 加
– 減
-表達(dá)式 一元負(fù), 也可以作為反轉(zhuǎn)(反轉(zhuǎn)表達(dá)式的符號(hào))
- 乘
/ 除
~/ 除并取整
% 取模
assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // 結(jié)果是一個(gè)浮點(diǎn)數(shù)
assert(5 ~/ 2 == 2); // 結(jié)果是一個(gè)整數(shù)
assert(5 % 2 == 1); // 取余
assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
Dart 還支持自增自減操作栈顷。
Operator
++var
var = var + 1 (表達(dá)式的值為 var + 1)
var++ var = var + 1 (表達(dá)式的值為 var)
--var var = var – 1 (表達(dá)式的值為 var – 1)
var-- var = var – 1 (表達(dá)式的值為 var)
var a, b;
a = 0;
b = ++a; // 在 b 賦值前將 a 增加 1逆日。
assert(a == b); // 1 == 1
a = 0;
b = a++; // 在 b 賦值后將 a 增加 1。
assert(a != b); // 1 != 0
a = 0;
b = --a; // 在 b 賦值前將 a 減少 1萄凤。
assert(a == b); // -1 == -1
a = 0;
b = a--; // 在 b 賦值后將 a 減少 1屏富。
assert(a != b); // -1 != 0
關(guān)系運(yùn)算符
下表列出了關(guān)系運(yùn)算符及含義:
|
Operator
==
|
相等
|
| --- | --- |
| !=
| 不等 |
| >
| 大于 |
| <
| 小于 |
| >=
| 大于等于 |
| <=
| 小于等于 |
要判斷兩個(gè)對(duì)象 x 和 y 是否表示相同的事物使用 ==
即可。(在極少數(shù)情況下蛙卤,可能需要使用 identical() 函數(shù)來確定兩個(gè)對(duì)象是否完全相同狠半。)。下面是 ==
運(yùn)算符的一些規(guī)則:
假設(shè)有變量 x 和 y颤难,且 x 和 y 至少有一個(gè)為 null神年,則當(dāng)且僅當(dāng) x 和 y 均為 null 時(shí) x == y 才會(huì)返回 true,否則只有一個(gè)為 null 則返回 false行嗤。
*x*.==(*y*)
將會(huì)返回值已日,這里不管有沒有 y,即 y 是可選的栅屏。也就是說==
其實(shí)是 x 中的一個(gè)方法飘千,并且可以被重寫堂鲜。詳情請(qǐng)查閱重寫運(yùn)算符。
下面的代碼給出了每一種關(guān)系運(yùn)算符的示例:
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
類型判斷運(yùn)算符
as
护奈、is
缔莲、is!
運(yùn)算符是在運(yùn)行時(shí)判斷對(duì)象類型的運(yùn)算符。
|
Operator
as
|
類型轉(zhuǎn)換(也用作指定類前綴))
|
| --- | --- |
| is
| 如果對(duì)象是指定類型則返回 true |
| is!
| 如果對(duì)象是指定類型則返回 false |
當(dāng)且僅當(dāng) obj
實(shí)現(xiàn)了 T
的接口霉旗,obj is T
才是 true痴奏。例如 obj is Object
總為 true,因?yàn)樗蓄惗际?Object 的子類厌秒。
使用 as
操作符可以把對(duì)象轉(zhuǎn)換為特定的類型读拆。一般情況下可以將其當(dāng)做 is
判定類型后調(diào)用所判定對(duì)象的函數(shù)的縮寫形式。假設(shè)有如下代碼:
if (emp is Person) {
// 類型檢查
emp.firstName = 'Bob';
}
你可以使用 as 運(yùn)算符進(jìn)行縮寫:
(emp as Person).firstName = 'Bob';
賦值運(yùn)算符
可以使用 = 來賦值鸵闪,同時(shí)也可以使用 ??= 來為值為 null 的變量賦值檐晕。
// 將 value 賦值給 a
a = value;
// 當(dāng)且僅當(dāng) b 為 null 時(shí)才賦值
b ??= value;
像 += 這樣的賦值運(yùn)算符將算數(shù)運(yùn)算符和賦值運(yùn)算符組合在了一起。
var a = 2; // 使用 = 賦值
a *= 3; // 賦值并做乘法運(yùn)算:a = a * 3
assert(a == 6);
邏輯運(yùn)算符
使用邏輯運(yùn)算符你可以反轉(zhuǎn)或組合布爾表達(dá)式蚌讼。
運(yùn)算符 描述
!!表達(dá)式 對(duì)表達(dá)式結(jié)果取反(即將 true 變?yōu)?false辟灰,false 變?yōu)?true)
|| 邏輯或
&& 邏輯與
if (!done && (col == 0 || col == 3)) {
// ...Do something...
}
按位和移位運(yùn)算符
在 Dart 中,二進(jìn)制位運(yùn)算符可以操作二進(jìn)制的某一位啦逆,但僅適用于整數(shù)伞矩。
& 按位與
| 按位或
^ 按位異或
~表達(dá)式 按位取反(即將 “0” 變?yōu)?“1”笛洛,“1” 變?yōu)?“0”)
<< 位左移
位右移
final value = 0x22;
final bitmask = 0x0f;
assert((value & bitmask) == 0x02); // 按位與
assert((value & ~bitmask) == 0x20); // 取反后按位與
assert((value | bitmask) == 0x2f); // 按位或
assert((value ^ bitmask) == 0x2d); // 按位異或
assert((value << 4) == 0x220); // 位左移
assert((value >> 4) == 0x02); // 位右移
條件表達(dá)式
Dart 有兩個(gè)特殊的運(yùn)算符可以用來替代 if-else 語(yǔ)句:
condition ? expr1 : expr2
條件 ? 表達(dá)式 1 : 表達(dá)式 2:如果條件為 true夏志,執(zhí)行表達(dá)式 1并返回執(zhí)行結(jié)果,否則執(zhí)行表達(dá)式 2 并返回執(zhí)行結(jié)果苛让。
expr1 ?? expr2
表達(dá)式 1 ?? 表達(dá)式 2:如果表達(dá)式 1 為非 null 則返回其值沟蔑,否則執(zhí)行表達(dá)式 2 并返回其值。
如果賦值是根據(jù)布爾表達(dá)式則考慮使用 ?
:狱杰。
var visibility = isPublic ? 'public' : 'private';
如果賦值是根據(jù)判定是否為 null 則考慮使用??
瘦材。
String playerName(String name) => name ?? 'Guest';
// 相對(duì)使用 ?: 運(yùn)算符來說稍微長(zhǎng)了點(diǎn)。
String playerName(String name) => name != null ? name : 'Guest';
// 如果使用 if-else 則更長(zhǎng)仿畸。
String playerName(String name) {
if (name != null) {
return name;
} else {
return 'Guest';
}
}
級(jí)聯(lián)運(yùn)算符(..)
級(jí)聯(lián)運(yùn)算符(..)可以讓你在同一個(gè)對(duì)象上連續(xù)調(diào)用多個(gè)對(duì)象的變量或方法食棕。
比如下面的代碼:
querySelector('#confirm') // 獲取對(duì)象。
..text = 'Confirm' // 使用對(duì)象的成員错沽。
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
第一個(gè)方法 querySelector 返回了一個(gè) Selector 對(duì)象簿晓,后面的級(jí)聯(lián)操作符都是調(diào)用這個(gè) Selector 對(duì)象的成員并忽略每個(gè)操作的返回值。
上面的代碼相當(dāng)于:
var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
級(jí)聯(lián)運(yùn)算符可以嵌套千埃,例如:
final addressBook = (AddressBookBuilder()
..name = 'jenny'
..email = 'jenny@example.com'
..phone = (PhoneNumberBuilder()
..number = '415-555-0100'
..label = 'home')
.build())
.build();
在返回對(duì)象的函數(shù)中謹(jǐn)慎使用級(jí)聯(lián)操作符憔儿。例如,下面的代碼是錯(cuò)誤的:
var sb = StringBuffer();
sb.write('foo')
..write('bar'); // 出錯(cuò):void 對(duì)象中沒有方法 write放可。
上述代碼中的 sb.write() 方法返回的是 void谒臼,返回值為 void 的方法則不能使用級(jí)聯(lián)運(yùn)算符朝刊。
其他運(yùn)算符
大多數(shù)其它的運(yùn)算符,已經(jīng)在其它的示例中使用過:
運(yùn)算符 | 名字 | 描述 |
---|---|---|
() |
使用方法 | 代表調(diào)用一個(gè)方法 |
[] |
訪問 List | 訪問 List 中特定位置的元素 |
. |
訪問成員 | 成員訪問符 |
?. |
條件訪問成員 | 與上述成員訪問符類似蜈缤,但是左邊的操作對(duì)象不能為 null拾氓,例如 foo?.bar,如果 foo 為 null 則返回 null 劫樟,否則返回 bar |
更多關(guān)于 .
, ?.
和 ..
運(yùn)算符介紹痪枫,請(qǐng)參考類.
流程控制語(yǔ)句
你可以使用下面的語(yǔ)句來控制 Dart 代碼的執(zhí)行流程:
if
和else
for
循環(huán)while
和do
-while
循環(huán)break
和continue
switch
和case
assert
使用 try-catch
和 throw
也能影響控制流,詳情參考異常部分叠艳。
If 和 Else
Dart 支持 if - else
語(yǔ)句奶陈,其中 else
是可選的,比如下面的例子附较。你也可以參考條件表達(dá)式吃粒。
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
與 JavaScript 不同的是,Dart 的 if 語(yǔ)句中的條件必須是一個(gè)布爾值拒课,不能是其它類型徐勃。詳情請(qǐng)查閱布爾值。
For 循環(huán)
你可以使用標(biāo)準(zhǔn)的 for 循環(huán)進(jìn)行迭代早像。例如:
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
在 Dart 語(yǔ)言中僻肖,for 循環(huán)中的閉包會(huì)自動(dòng)捕獲循環(huán)的 索引值 以避免 JavaScript 中一些常見的陷阱。假設(shè)有如下代碼:\
var callbacks = [];
for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());
上述代碼執(zhí)行后會(huì)輸出 0
和 1
卢鹦,但是如果在 JavaScript 中執(zhí)行同樣的代碼則會(huì)輸出兩個(gè) 2
臀脏。
如果要遍歷的對(duì)象實(shí)現(xiàn)了 Iterable 接口,則可以使用 forEach() 方法冀自,如果不需要使用到索引揉稚,則使用 forEach
方法是一個(gè)非常好的選擇:
candidates.forEach((candidate) => candidate.interview());
像 List 和 Set 等實(shí)現(xiàn)了 Iterable 接口的類還支持 for-in
形式的迭代:
var collection = [0, 1, 2];
for (var x in collection) {
print(x); // 0 1 2
}
While 和 Do-While
while 循環(huán)會(huì)在執(zhí)行循環(huán)體前先判斷條件:
while (!isDone()) {
doSomething();
}
do-while 循環(huán)則會(huì)先執(zhí)行一遍循環(huán)體 再 判斷條件:
do {
printLine();
} while (!atEndOfPage());
Break 和 Continue
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
使用continue
可以跳過本次循環(huán)直接進(jìn)入下一次循環(huán):
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
上述代碼中的 candidates 如果像 List 或 Set 一樣實(shí)現(xiàn)了 Iterable 接口則可以簡(jiǎn)單地使用下述寫法:
candidates
.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());
Switch 和 Case
Switch 語(yǔ)句在 Dart 中使用 ==
來比較整數(shù)、字符串或編譯時(shí)常量熬粗,比較的兩個(gè)對(duì)象必須是同一個(gè)類型且不能是子類并且沒有重寫 ==
操作符搀玖。枚舉類型非常適合在 Switch
語(yǔ)句中使用。
每一個(gè)非空的 case 子句都必須有一個(gè) break 語(yǔ)句驻呐,也可以???過 continue灌诅、throw 或者 return 來結(jié)束非空 case 語(yǔ)句。
當(dāng)沒有 case 語(yǔ)句匹配時(shí)含末,可以使用 default 子句來匹配這種情況:
var command = 'OPEN';
switch (command) {
case 'CLOSED':
executeClosed();
break;
case 'PENDING':
executePending();
break;
case 'APPROVED':
executeApproved();
break;
case 'DENIED':
executeDenied();
break;
case 'OPEN':
executeOpen();
break;
default:
executeUnknown();
}
下面的例子忽略了 case 子句的 break 語(yǔ)句猜拾,因此會(huì)產(chǎn)生錯(cuò)誤:
var command = 'OPEN';
switch (command) {
case 'OPEN':
executeOpen();
// 錯(cuò)誤: 沒有 break
case 'CLOSED':
executeClosed();
break;
}
但是,Dart 支持空的 case 語(yǔ)句答渔,允許其以 fall-through 的形式執(zhí)行关带。
var command = 'CLOSED';
switch (command) {
case 'CLOSED': // case 語(yǔ)句為空時(shí)的 fall-through 形式。
case 'NOW_CLOSED':
// case 條件值為 CLOSED 和 NOW_CLOSED 時(shí)均會(huì)執(zhí)行該語(yǔ)句。
executeNowClosed();
break;
}
在非空 case 語(yǔ)句中想要實(shí)現(xiàn) fall-through 的形式宋雏,可以使用 continue 語(yǔ)句配合 lable 的方式實(shí)現(xiàn):
var command = 'CLOSED';
switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;
// 繼續(xù)執(zhí)行標(biāo)簽為 nowClosed 的 case 子句芜飘。
nowClosed:
case 'NOW_CLOSED':
// case 條件值為 CLOSED 和 NOW_CLOSED 時(shí)均會(huì)執(zhí)行該語(yǔ)句。
executeNowClosed();
break;
}
每個(gè) case 子句都可以有局部變量且僅在該 case 語(yǔ)句內(nèi)可見磨总。
斷言
在開發(fā)過程中嗦明,可以在條件表達(dá)式為 false 時(shí)使用 - assert(條件, 可選信息); - 語(yǔ)句來打斷代碼的執(zhí)行。你可以在本文中找到大量使用 assert 的例子蚪燕。下面是相關(guān)示例:
// 確保變量值不為 null娶牌。
assert(text != null);
// 確保變量值小于 100。
assert(number < 100);
// 確保這是一個(gè) https 地址馆纳。
assert(urlString.startsWith('https'));
assert 的第二個(gè)參數(shù)可以為其添加一個(gè)字符串消息诗良。
assert(urlString.startsWith('https'),
'URL ($urlString) should start with "https".');