本文適合有代碼基礎(chǔ)的人,如果沒(méi)在代碼基礎(chǔ)請(qǐng)文章底部來(lái)源從頭開(kāi)始學(xué)習(xí)
示例
// 定義一個(gè)函數(shù)
printInteger(int aNumber) {
print('The number is $aNumber.'); // 打印到控制臺(tái)赫舒。
}
// 應(yīng)用從這里開(kāi)始執(zhí)行沙郭。
// 程序開(kāi)始執(zhí)行函數(shù),該函數(shù)是特定的秉撇、必須的、頂級(jí)函數(shù)就缆。
main() {
//定義變量颜价,通過(guò)這種方式定義變量不需要指定變量類(lèi)型。
var number = 42;
printInteger(number); // 調(diào)用函數(shù)一死。
}
重要的概念
在學(xué)習(xí) Dart 語(yǔ)言時(shí), 應(yīng)該基于以下事實(shí)和概念:
任何保存在變量中的都是一個(gè) 對(duì)象 , 并且所有的對(duì)象都是對(duì)應(yīng)一個(gè) 類(lèi) 的實(shí)例傻唾。 無(wú)論是數(shù)字投慈,函數(shù)和 null 都是對(duì)象承耿。所有對(duì)象繼承自 Object 類(lèi)。
盡管 Dart 是強(qiáng)類(lèi)型的伪煤,但是 Dart 可以推斷類(lèi)型加袋,所以類(lèi)型注釋是可選的。 在上面的代碼中抱既, number 被推斷為 int 類(lèi)型职烧。 如果要明確說(shuō)明不需要任何類(lèi)型, 需要使用特殊類(lèi)型 dynamic 防泵。
Dart 支持泛型蚀之,如 List <int> (整數(shù)列表)或 List <dynamic> (任何類(lèi)型的對(duì)象列表)。
Dart 支持頂級(jí)函數(shù)(例如 main() )捷泞, 同樣函數(shù)綁定在類(lèi)或?qū)ο笊希ǚ謩e是 靜態(tài)函數(shù) 和 實(shí)例函數(shù) )足删。 以及支持函數(shù)內(nèi)創(chuàng)建函數(shù) ( 嵌套 或 局部函數(shù) ) 。
類(lèi)似地肚邢, Dart 支持頂級(jí) 變量 壹堰, 同樣變量綁定在類(lèi)或?qū)ο笊希o態(tài)變量和實(shí)例變量)。 實(shí)例變量有時(shí)稱(chēng)為字段或?qū)傩浴?/p>
與 Java 不同骡湖,Dart 沒(méi)有關(guān)鍵字 “public” , “protected” 和 “private” 峻厚。 如果標(biāo)識(shí)符以下劃線(xiàn)(_)開(kāi)頭响蕴,則它相對(duì)于庫(kù)是私有的。 有關(guān)更多信息惠桃,參考 庫(kù)和可見(jiàn)性浦夷。
標(biāo)識(shí)符 以字母或下劃線(xiàn)(_)開(kāi)頭,后跟任意字母和數(shù)字組合辜王。
Dart 語(yǔ)法中包含 表達(dá)式( expressions )(有運(yùn)行時(shí)值)和 語(yǔ)句( statements )(沒(méi)有運(yùn)行時(shí)值)劈狐。 例如,條件表達(dá)式 condition ? expr1 : expr2 的值可能是 expr1 或 expr2 呐馆。 將其與 if-else 語(yǔ)句 相比較肥缔,if-else 語(yǔ)句沒(méi)有值。 一條語(yǔ)句通常包含一個(gè)或多個(gè)表達(dá)式汹来,相反表達(dá)式不能直接包含語(yǔ)句续膳。
Dart 工具提示兩種類(lèi)型問(wèn)題:警告和錯(cuò)誤。 警告只是表明代碼可能無(wú)法正常工作收班,但不會(huì)阻止程序的執(zhí)行坟岔。 錯(cuò)誤可能是編譯時(shí)錯(cuò)誤或者運(yùn)行時(shí)錯(cuò)誤。 編譯時(shí)錯(cuò)誤會(huì)阻止代碼的執(zhí)行; 運(yùn)行時(shí)錯(cuò)誤會(huì)導(dǎo)致代碼在執(zhí)行過(guò)程中引發(fā) [異常](#exception)摔桦。
Dart關(guān)鍵字
key | 作用域 | 備注 | |
---|---|---|---|
abstract | 2 | 抽象方法/抽象類(lèi) | |
dynamic | 2 | ||
implements | 2 | ||
show | 1 | ||
as | 2 | ||
else | |||
import | 2 | ||
static | 2 | ||
assert | |||
enum | |||
in | |||
super | |||
async | 1 | ||
export | 2 | ||
interface | 2 | ||
switch | |||
await | 3 | ||
extends | |||
is | |||
sync | 1 | ||
break | |||
external | 2 | ||
library | 2 | ||
this | |||
case | |||
factory | 2 | ||
mixin | 2 | ||
throw | |||
catch | |||
false | |||
new | |||
true | |||
class | |||
final | |||
null | |||
try | |||
const | |||
finally | |||
on | 1 | ||
typedef | 2 | ||
continue | |||
for | |||
operator | 2 | ||
var | |||
covariant | 2 | ||
Function | 2 | ||
part | 2 | ||
void | |||
default | |||
get | 2 | ||
rethrow | |||
while | |||
deferred | 2 | ||
hide | 1 | ||
return | |||
with | |||
do | |||
if | |||
set | 2 | ||
yield | 3 |
避免使用這些單詞作為標(biāo)識(shí)符社付。 但是,如有必要,標(biāo)有上標(biāo)的關(guān)鍵字可以用作標(biāo)識(shí)符:
帶有 1 上標(biāo)的單詞為 上下文關(guān)鍵字鸥咖, 僅在特定位置具有含義纪隙。 他們?cè)谌魏蔚胤蕉际怯行У臉?biāo)識(shí)符。
帶有 2 上標(biāo)的單詞為 內(nèi)置標(biāo)識(shí)符扛或, 為了簡(jiǎn)化將 JavaScript 代碼移植到 Dart 的工作绵咱, 這些關(guān)鍵字在大多數(shù)地方都是有效的標(biāo)識(shí)符, 但它們不能用作類(lèi)或類(lèi)型名稱(chēng)熙兔,也不能用作 import 前綴悲伶。
帶有 3 上標(biāo)的單詞是與 Dart 1.0 發(fā)布后添加的異步支持相關(guān)的更新,作為限制類(lèi)保留字住涉。
不能在標(biāo)記為 async 麸锉,async* 或 sync* 的任何函數(shù)體中使用 await 或 yield 作為標(biāo)識(shí)符。
關(guān)鍵字表中的剩余單詞都是保留字舆声。 不能將保留字用作標(biāo)識(shí)符花沉。
abstract
- 抽象方法
實(shí)例方法, getter媳握, 和 setter 方法可以是抽象的碱屁, 只定義接口不進(jìn)行實(shí)現(xiàn),而是留給其他類(lèi)去實(shí)現(xiàn)蛾找。 抽象方法只存在于 抽象類(lèi) 中娩脾。
定義一個(gè)抽象函數(shù),使用分號(hào) (;) 來(lái)代替函數(shù)體:
abstract class Doer {
// 定義實(shí)例變量和方法 ...
void doSomething(); // 定義一個(gè)抽象方法打毛。
}
class EffectiveDoer extends Doer {
void doSomething() {
// 提供方法實(shí)現(xiàn)柿赊,所以這里的方法就不是抽象方法了...
}
}
調(diào)用抽象方法會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤。
- 抽象類(lèi)
使用 abstract 修飾符來(lái)定義 抽象類(lèi) — 抽象類(lèi)不能實(shí)例化幻枉。 抽象類(lèi)通常用來(lái)定義接口碰声,以及部分實(shí)現(xiàn)。 如果希望抽象類(lèi)能夠被實(shí)例化熬甫,那么可以通過(guò)定義一個(gè) 工廠(chǎng)構(gòu)造函數(shù) 來(lái)實(shí)現(xiàn)胰挑。
抽象類(lèi)通常具有 抽象方法。 下面是一個(gè)聲明具有抽象方法的抽象類(lèi)示例:
// 這個(gè)類(lèi)被定義為抽象類(lèi)罗珍,
// 所以不能被實(shí)例化洽腺。
abstract class AbstractContainer {
// 定義構(gòu)造行數(shù),字段覆旱,方法...
void updateChildren(); // 抽象方法蘸朋。
}
dynamic
使用 dynamic 注解替換推斷失敗的情況邑茄。
Dart 允許在許多地方省略類(lèi)型注解胰丁,并嘗試推斷類(lèi)型蛉签。在某些情況下,如果推斷失敗了亡脑,會(huì)默認(rèn)指定為 dynamic 類(lèi)型次哈。如果 dynamic 類(lèi)型與期望相同莹规,那么從技術(shù)的角度來(lái)講请梢,這是獲取類(lèi)型最簡(jiǎn)潔 的方式。
但是辐马,這種方式是最不清晰的拷橘。任何一個(gè)閱讀代碼的人,當(dāng)看到一個(gè)類(lèi)型確實(shí)的成員時(shí)喜爷,是沒(méi)有辦法 知道冗疮,編寫(xiě)的人是希望它是 dynamic 類(lèi)型,還是期望它是其他的什么類(lèi)型檩帐,或者閱讀的人就簡(jiǎn)單的 認(rèn)為是編寫(xiě)的人忘記了指定類(lèi)型术幔。
當(dāng) dynamic 是你期望的類(lèi)型,就應(yīng)該指明它湃密,這樣能讓你的意圖更清晰诅挑。
dynamic mergeJson(dynamic original, dynamic changes) => ...
在Dart 2之前,本規(guī)則恰恰是相反的:不要 為隱性類(lèi)型的成員指定 dynamic 注解泛源“瓮祝基于強(qiáng)類(lèi)型系統(tǒng) 和類(lèi)型推斷,現(xiàn)在的開(kāi)發(fā)者更希望 Dart 的行為類(lèi)似于推斷的靜態(tài)類(lèi)型語(yǔ)言俩由《镜眨基于這種心理模型,我們發(fā)現(xiàn) 代碼區(qū)域慢慢地失去了靜態(tài)類(lèi)型所具有的安全及性能幻梯。
implements
每個(gè)類(lèi)都隱式的定義了一個(gè)接口,接口包含了該類(lèi)所有的實(shí)例成員及其實(shí)現(xiàn)的接口努释。 如果要?jiǎng)?chuàng)建一個(gè) A 類(lèi)碘梢,A 要支持 B 類(lèi)的 API ,但是不需要繼承 B 的實(shí)現(xiàn)伐蒂, 那么可以通過(guò) A 實(shí)現(xiàn) B 的接口煞躬。
一個(gè)類(lèi)可以通過(guò) implements 關(guān)鍵字來(lái)實(shí)現(xiàn)一個(gè)或者多個(gè)接口, 并實(shí)現(xiàn)每個(gè)接口要求的 API逸邦。 例如:
// person 類(lèi)恩沛。 隱式接口里面包含了 greet() 方法聲明。
class Person {
// 包含在接口里缕减,但只在當(dāng)前庫(kù)中可見(jiàn)雷客。
final _name;
// 不包含在接口里,因?yàn)檫@是一個(gè)構(gòu)造函數(shù)桥狡。
Person(this._name);
// 包含在接口里搅裙。
String greet(String who) => 'Hello, $who. I am $_name.';
}
// person 接口的實(shí)現(xiàn)皱卓。
class Impostor implements Person {
get _name => '';
String greet(String who) => 'Hi $who. Do you know who I am?';
}
String greetBob(Person person) => person.greet('Bob');
void main() {
print(greetBob(Person('Kathy')));
print(greetBob(Impostor()));
}
下面示例演示一個(gè)類(lèi)如何實(shí)現(xiàn)多個(gè)接口: Here’s an example of specifying that a class implements multiple interfaces:
class Point implements Comparable, Location {...}
show hide
導(dǎo)入庫(kù)的一部分
如果你只使用庫(kù)的一部分功能,則可以選擇需要導(dǎo)入的 內(nèi)容部逮。例如:
// Import only foo.
import 'package:lib1/lib1.dart' show foo;
// Import all names EXCEPT foo.
import 'package:lib2/lib2.dart' hide foo;
as
- 類(lèi)型判定運(yùn)算符
as娜汁, is, 和 is! 運(yùn)算符用于在運(yùn)行時(shí)處理類(lèi)型檢查:
|Operator| Meaning|
| --- | ---|
|as| Typecast (也被用于指定庫(kù)前綴)|
|is |True if the object has the specified type|
|is!| False if the object has the specified type|
例如兄朋, obj is Object 總是 true掐禁。 但是只有 obj 實(shí)現(xiàn)了 T 的接口時(shí), obj is T 才是 true颅和。
使用 as 運(yùn)算符將對(duì)象強(qiáng)制轉(zhuǎn)換為特定類(lèi)型傅事。 通常,可以認(rèn)為是 is 類(lèi)型判定后融虽,被判定對(duì)象調(diào)用函數(shù)的一種縮寫(xiě)形式享完。 請(qǐng)考慮以下代碼:
```
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
```
使用 as 運(yùn)算符進(jìn)行縮寫(xiě):
```
(emp as Person).firstName = 'Bob';
```
######提示:以上代碼并不是等價(jià)的。 如果 emp 為 null 或者不是 Person 對(duì)象有额, 那么第一個(gè) is 的示例般又,后面將不回執(zhí)行; 第二個(gè) as 的示例會(huì)拋出異常巍佑。
-
指定庫(kù)前綴
如果導(dǎo)入兩個(gè)存在沖突標(biāo)識(shí)符的庫(kù)茴迁, 則可以為這兩個(gè)庫(kù),或者其中一個(gè)指定前綴萤衰。 例如堕义,如果 library1 和 library2 都有一個(gè) Element 類(lèi), 那么可以通過(guò)下面的方式處理:import 'package:lib1/lib1.dart'; import 'package:lib2/lib2.dart' as lib2; // 使用 lib1 中的 Element脆栋。 Element element1 = Element(); // 使用 lib2 中的 Element倦卖。 lib2.Element element2 = lib2.Element();
if else
Dart 支持 if - else 語(yǔ)句,其中 else 是可選的椿争, 比如下面的例子怕膛, 另參考 conditional expressions.
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
和 JavaScript 不同, Dart 的判斷條件必須是布爾值秦踪,不能是其他類(lèi)型褐捻。
import
使用庫(kù)
通過(guò) import 指定一個(gè)庫(kù)命名空間中的內(nèi)如如何在另一個(gè)庫(kù)中使用。 例如椅邓,Dart Web應(yīng)用程序通常使用 dart:html 庫(kù)柠逞,它們可以像這樣導(dǎo)入:
import 'dart:html';
import 參數(shù)只需要一個(gè)指向庫(kù)的 URI。 對(duì)于內(nèi)置庫(kù)景馁,URI 擁有自己特殊的dart: 方案板壮。 對(duì)于其他的庫(kù),使用系統(tǒng)文件路徑或者 package: 方案 裁僧。 package: 方案指定由包管理器(如 pub 工具)提供的庫(kù)个束。例如:
import 'package:test/test.dart';
提示: URI 代表統(tǒng)一資源標(biāo)識(shí)符慕购。 URL(統(tǒng)一資源定位符)是一種常見(jiàn)的URI。
static
類(lèi)變量和方法
使用 static 關(guān)鍵字實(shí)現(xiàn)類(lèi)范圍的變量和方法茬底。
-
靜態(tài)變量
靜態(tài)變量(類(lèi)變量)對(duì)于類(lèi)級(jí)別的狀態(tài)是非常有用的:class Queue { static const initialCapacity = 16; // ··· } void main() { assert(Queue.initialCapacity == 16); }
靜態(tài)變量只到它們被使用的時(shí)候才會(huì)初始化沪悲。
提示: 代碼準(zhǔn)守風(fēng)格推薦指南 中的命名規(guī)則, 使用 lowerCamelCase 來(lái)命名常量阱表。
-
靜態(tài)方法
靜態(tài)方法(類(lèi)方法)不能在實(shí)例上使用殿如,因此它們不能訪(fǎng)問(wèn) this 。 例如:import 'dart:math'; class Point { num x, y; Point(this.x, this.y); static num distanceBetween(Point a, Point b) { var dx = a.x - b.x; var dy = a.y - b.y; return sqrt(dx * dx + dy * dy); } } void main() { var a = Point(2, 2); var b = Point(4, 4); var distance = Point.distanceBetween(a, b); assert(2.8 < distance && distance < 2.9); print(distance); }
提示: 對(duì)于常見(jiàn)或廣泛使用的工具和函數(shù)最爬, 應(yīng)該考慮使用頂級(jí)函數(shù)而不是靜態(tài)方法涉馁。
靜態(tài)函數(shù)可以當(dāng)做編譯時(shí)常量使用。 例如爱致,可以將靜態(tài)方法作為參數(shù)傳遞給常量構(gòu)造函數(shù)烤送。
asset
如果 assert 語(yǔ)句中的布爾條件為 false , 那么正常的程序執(zhí)行流程會(huì)被中斷糠悯。 在本章中包含部分 assert 的使用帮坚, 下面是一些示例:
// 確認(rèn)變量值不為空。
assert(text != null);
// 確認(rèn)變量值小于100互艾。
assert(number < 100);
// 確認(rèn) URL 是否是 https 類(lèi)型试和。
assert(urlString.startsWith('https'));
提示: assert 語(yǔ)句只在開(kāi)發(fā)環(huán)境中有效, 在生產(chǎn)環(huán)境是無(wú)效的纫普; Flutter 中的 assert 只在 debug 模式 中有效阅悍。 開(kāi)發(fā)用的工具,例如 dartdevc 默認(rèn)是開(kāi)啟 assert 功能昨稼。 其他的一些工具节视, 例如 dart 和 dart2js, 支持通過(guò)命令行開(kāi)啟 assert : --enable-asserts。
assert 的第二個(gè)參數(shù)可以為其添加一個(gè)字符串消息假栓。
assert(urlString.startsWith('https'),
'URL ($urlString) should start with "https".');
assert 的第一個(gè)參數(shù)可以是解析為布爾值的任何表達(dá)式肴茄。 如果表達(dá)式結(jié)果為 true , 則斷言成功但指,并繼續(xù)執(zhí)行。 如果表達(dá)式結(jié)果為 false 抗楔, 則斷言失敗棋凳,并拋出異常 (AssertionError) 。
enum
枚舉類(lèi)型
枚舉類(lèi)型也稱(chēng)為 enumerations 或 enums 连躏, 是一種特殊的類(lèi)剩岳,用于表示數(shù)量固定的常量值。
使用枚舉
使用 enum 關(guān)鍵字定義一個(gè)枚舉類(lèi)型:
enum Color { red, green, blue }
枚舉中的每個(gè)值都有一個(gè) index getter 方法入热, 該方法返回值所在枚舉類(lèi)型定義中的位置(從 0 開(kāi)始)拍棕。 例如晓铆,第一個(gè)枚舉值的索引是 0 , 第二個(gè)枚舉值的索引是 1绰播。
assert(Color.red.index == 0);
assert(Color.green.index == 1);
assert(Color.blue.index == 2);
使用枚舉的 values 常量骄噪, 獲取所有枚舉值列表( list )。
List<Color> colors = Color.values;
assert(colors[2] == Color.blue);
可以在 switch 語(yǔ)句 中使用枚舉蠢箩, 如果不處理所有枚舉值链蕊,會(huì)收到警告:
var aColor = Color.blue;
switch (aColor) {
case Color.red:
print('Red as roses!');
break;
case Color.green:
print('Green as grass!');
break;
default: // 沒(méi)有這個(gè),會(huì)看到一個(gè)警告谬泌。
print(aColor); // 'Color.blue'
}
枚舉類(lèi)型具有以下限制:
- 枚舉不能被子類(lèi)化滔韵,混合或?qū)崿F(xiàn)。
- 枚舉不能被顯式實(shí)例化掌实。
有關(guān)更多信息陪蜻,參考 Dart language specification 。
for in
for 循環(huán)
進(jìn)行迭代操作贱鼻,可以使用標(biāo)準(zhǔn) for 語(yǔ)句宴卖。 例如:
var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
message.write('!');
}
閉包在 Dart 的 for 循環(huán)中會(huì)捕獲循環(huán)的 index 索引值, 來(lái)避免 JavaScript 中常見(jiàn)的陷阱忱嘹。 請(qǐng)思考示例代碼:
var callbacks = [];
for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());
和期望一樣嘱腥,輸出的是 0 和 1。 但是示例中的代碼在 JavaScript 中會(huì)連續(xù)輸出兩個(gè) 2 拘悦。
I如果要迭代一個(gè)實(shí)現(xiàn)了 Iterable 接口的對(duì)象齿兔, 可以使用 forEach() 方法, 如果不需要使用當(dāng)前計(jì)數(shù)值础米, 使用 forEach() 是非常棒的選擇分苇;
candidates.forEach((candidate) => candidate.interview());
實(shí)現(xiàn)了 Iterable 的類(lèi)(比如, List 和 Set)同樣也支持使用 for-in 進(jìn)行迭代操作 iteration :
var collection = [0, 1, 2];
for (var x in collection) {
print(x); // 0 1 2
}
extends super
擴(kuò)展類(lèi)(繼承)
使用 extends 關(guān)鍵字來(lái)創(chuàng)建子類(lèi)屁桑, 使用 super 關(guān)鍵字來(lái)引用父類(lèi):
class Television {
void turnOn() {
_illuminateDisplay();
_activateIrSensor();
}
// ···
}
class SmartTelevision extends Television {
void turnOn() {
super.turnOn();
_bootNetworkInterface();
_initializeMemory();
_upgradeApps();
}
// ···
}
async await
- 異步支持
Dart 庫(kù)中包含許多返回 Future 或 Stream 對(duì)象的函數(shù). 這些函數(shù)在設(shè)置完耗時(shí)任務(wù)(例如 I/O 曹組)后医寿, 就立即返回了,不會(huì)等待耗任務(wù)完成蘑斧。 使用 async 和 await 關(guān)鍵字實(shí)現(xiàn)異步編程靖秩。 可以讓你像編寫(xiě)同步代碼一樣實(shí)現(xiàn)異步操作。
- 處理 Future
可以通過(guò)下面兩種方式竖瘾,獲得 Future 執(zhí)行完成的結(jié)果:
使用 async 和 await.
使用 Future API沟突,具體描述,參考 庫(kù)概覽.
使用 async 和 await 關(guān)鍵字的代碼是異步的捕传。 雖然看起來(lái)有點(diǎn)想同步代碼惠拭。 例如,下面的代碼使用 await 等待異步函數(shù)的執(zhí)行結(jié)果庸论。
```
await lookUpVersion();
```
要使用 await 职辅, 代碼必須在 異步函數(shù)(使用 async 標(biāo)記的函數(shù))中:
```
Future checkVersion() async {
var version = await lookUpVersion();
// Do something with version
}
```
提示: 雖然異步函數(shù)可能會(huì)執(zhí)行耗時(shí)的操作棒呛, 但它不會(huì)等待這些操作。 相反域携,異步函數(shù)只有在遇到第一個(gè) await 表達(dá)式(詳情見(jiàn))時(shí)才會(huì)執(zhí)行簇秒。 也就是說(shuō),它返回一個(gè) Future 對(duì)象涵亏, 僅在await表達(dá)式完成后才恢復(fù)執(zhí)行宰睡。
使用 try, catch气筋, 和 finally 來(lái)處理代碼中使用 await 導(dǎo)致的錯(cuò)誤拆内。
```
try {
version = await lookUpVersion();
} catch (e) {
// React to inability to look up the version
}
```
在一個(gè)異步函數(shù)中可以多次使用 await 。 例如宠默,下面代碼中等待了三次函數(shù)結(jié)果:
```
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);
```
在 await 表達(dá)式 中麸恍, 表達(dá)式 的值通常是一個(gè) Future 對(duì)象; 如果不是搀矫,這是表達(dá)式的值會(huì)被自動(dòng)包裝成一個(gè) Future 對(duì)象抹沪。 Future 對(duì)象指明返回一個(gè)對(duì)象的承諾(promise)。 await 表達(dá)式 執(zhí)行的結(jié)果為這個(gè)返回的對(duì)象瓤球。 await 表達(dá)式會(huì)阻塞代碼的執(zhí)行融欧,直到需要的對(duì)象返回為止。
如果在使用 await 導(dǎo)致編譯時(shí)錯(cuò)誤卦羡, 確認(rèn) await 是否在一個(gè)異步函數(shù)中噪馏。 例如,在應(yīng)用的 main() 函數(shù)中使用 await 绿饵, main() 函數(shù)的函數(shù)體必須被標(biāo)記為 async :
Future main() async {
checkVersion();
print('In main: version is ${await lookUpVersion()}');
}
-
聲明異步函數(shù)
函數(shù)體被 async 標(biāo)示符標(biāo)記的函數(shù)欠肾,即是一個(gè)異步函數(shù)。 將 async 關(guān)鍵字添加到函數(shù)使其返回Future拟赊。 例如刺桃,考慮下面的同步函數(shù),它返回一個(gè) String :String lookUpVersion() => '1.0.0';
例如吸祟,將來(lái)的實(shí)現(xiàn)將非常耗時(shí)瑟慈,將其更改為異步函數(shù),返回值是 Future 屋匕。
Future<String> lookUpVersion() async => '1.0.0';
注意封豪,函數(shù)體不需要使用Future API。 如有必要炒瘟, Dart 會(huì)創(chuàng)建 Future 對(duì)象。
如果函數(shù)沒(méi)有返回有效值第步, 需要設(shè)置其返回類(lèi)型為 Future<void> 疮装。
-
處理 Stream
當(dāng)需要從 Stream 中獲取數(shù)據(jù)值時(shí)缘琅, 可以通過(guò)一下兩種方式:使用 async 和 一個(gè) 異步循環(huán) (await for)。
使用 Stream API, 更多詳情廓推,參考 in the library tour刷袍。
提示: 在使用 await for 前,確保代碼清晰樊展, 并且確實(shí)希望等待所有流的結(jié)果呻纹。 例如,通常不應(yīng)該使用 await for 的UI事件偵聽(tīng)器专缠, 因?yàn)閁I框架會(huì)發(fā)送無(wú)窮無(wú)盡的事件流雷酪。一下是異步for循環(huán)的使用形式:
await for (varOrType identifier in expression) { // Executes each time the stream emits a value. }
上面 表達(dá)式 返回的值必須是 Stream 類(lèi)型。 執(zhí)行流程如下:
- 等待涝婉,直到流發(fā)出一個(gè)值哥力。
- 執(zhí)行 for 循環(huán)體,將變量設(shè)置為該發(fā)出的值
- 重復(fù)1和2墩弯,直到關(guān)閉流吩跋。
使用 break 或者 return 語(yǔ)句可以停止接收 stream 的數(shù)據(jù), 這樣就跳出了 for 循環(huán)渔工, 并且從 stream 上取消注冊(cè)锌钮。 如果在實(shí)現(xiàn)異步 for 循環(huán)時(shí)遇到編譯時(shí)錯(cuò)誤, 請(qǐng)檢查確保 await for 處于異步函數(shù)中引矩。 例如梁丘,要在應(yīng)用程序的 main() 函數(shù)中使用異步 fo r循環(huán), main() 函數(shù)體必須標(biāo)記為 async` :
Future main() async { // ... await for (var request in requestServer) { handleRequest(request); } // ... }
有關(guān)異步編程的更多信息脓魏,請(qǐng)參考 dart:async 部分兰吟。 同時(shí)也可參考文章 Dart Language Asynchrony Support: Phase 1 和 Dart Language Asynchrony Support: Phase 2, 以及 Dart language specification 。
switch case
在 Dart 中 switch 語(yǔ)句使用 == 比較整數(shù)茂翔,字符串混蔼,或者編譯時(shí)常量。 比較的對(duì)象必須都是同一個(gè)類(lèi)的實(shí)例(并且不可以是子類(lèi))珊燎, 類(lèi)必須沒(méi)有對(duì) == 重寫(xiě)惭嚣。 枚舉類(lèi)型 可以用于 switch 語(yǔ)句。
提示: 在 Dart 中 Switch 語(yǔ)句僅適用于有限的情況下悔政, 例如在 interpreter 或 scanner 中晚吞。
在 case 語(yǔ)句中,每個(gè)非空的 case 語(yǔ)句結(jié)尾需要跟一個(gè) break 語(yǔ)句谋国。 除 break 以外槽地,還有可以使用 continue, throw,者 return。
當(dāng)沒(méi)有 case 語(yǔ)句匹配時(shí)捌蚊,執(zhí)行 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ǔ)句集畅,導(dǎo)致錯(cuò)誤:
var command = 'OPEN';
switch (command) {
case 'OPEN':
executeOpen();
// ERROR: 丟失 break
case 'CLOSED':
executeClosed();
break;
}
但是, Dart 支持空 case 語(yǔ)句缅糟, 允許程序以 fall-through 的形式執(zhí)行挺智。
var command = 'CLOSED';
switch (command) {
case 'CLOSED': // Empty case falls through.
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}
在非空 case 中實(shí)現(xiàn) fall-through 形式, 可以使用 continue 語(yǔ)句結(jié)合 lable 的方式實(shí)現(xiàn):
var command = 'CLOSED';
switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;
// Continues executing at the nowClosed label.
nowClosed:
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}
case 語(yǔ)句可以擁有局部變量窗宦, 這些局部變量只能在這個(gè)語(yǔ)句的作用域中可見(jiàn)赦颇。
sync
生成器
當(dāng)您需要延遲生成( lazily produce )一系列值時(shí), 可以考慮使用生成器函數(shù)赴涵。 Dart 內(nèi)置支持兩種生成器函數(shù):
- Synchronous 生成器: 返回一個(gè) Iterable 對(duì)象媒怯。
- Asynchronous 生成器: 返回一個(gè) Stream 對(duì)象。
通過(guò)在函數(shù)體標(biāo)記 sync*句占, 可以實(shí)現(xiàn)一個(gè)同步生成器函數(shù)沪摄。 使用 yield 語(yǔ)句來(lái)傳遞值:
Iterable<int> naturalsTo(int n) sync* {
int k = 0;
while (k < n) yield k++;
}
通過(guò)在函數(shù)體標(biāo)記 async*, 可以實(shí)現(xiàn)一個(gè)異步生成器函數(shù)纱烘。 使用 yield 語(yǔ)句來(lái)傳遞值:
Stream<int> asynchronousNaturalsTo(int n) async* {
int k = 0;
while (k < n) yield k++;
}
如果生成器是遞歸的杨拐,可以使用 yield* 來(lái)提高其性能:
Iterable<int> naturalsDownFrom(int n) sync* {
if (n > 0) {
yield n;
yield* naturalsDownFrom(n - 1);
}
}
有關(guān)生成器的更多信息,請(qǐng)參考文章 Dart Language Asynchrony Support: Phase 2 擂啥。
break continue
使用 break 停止程序循環(huán):
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
使用 continue 跳轉(zhuǎn)到下一次迭代:
for (int i = 0; i < candidates.length; i++) {
var candidate = candidates[i];
if (candidate.yearsExperience < 5) {
continue;
}
candidate.interview();
}
如果對(duì)象實(shí)現(xiàn)了 Iterable 接口 (例如哄陶,list 或者 set)。 那么上面示例完全可以用另一種方式來(lái)實(shí)現(xiàn):
candidates
.where((c) => c.yearsExperience >= 5)
.forEach((c) => c.interview());
Mixin
為類(lèi)添加功能: Mixin
Mixin 是復(fù)用類(lèi)代碼的一種途徑哺壶, 復(fù)用的類(lèi)可以在不同層級(jí)屋吨,之間可以不存在繼承關(guān)系。
通過(guò) with 后面跟一個(gè)或多個(gè)混入的名稱(chēng)山宾,來(lái) 使用 Mixin 至扰, 下面的示例演示了兩個(gè)使用 Mixin 的類(lèi):
class Musician extends Performer with Musical {
// ···
}
class Maestro extends Person
with Musical, Aggressive, Demented {
Maestro(String maestroName) {
name = maestroName;
canConduct = true;
}
}
通過(guò)創(chuàng)建一個(gè)繼承自 Object 且沒(méi)有構(gòu)造函數(shù)的類(lèi),來(lái) 實(shí)現(xiàn) 一個(gè) Mixin 资锰。 如果 Mixin 不希望作為常規(guī)類(lèi)被使用敢课,使用關(guān)鍵字 mixin 替換 class 。 例如:
mixin Musical {
bool canPlayPiano = false;
bool canCompose = false;
bool canConduct = false;
void entertainMe() {
if (canPlayPiano) {
print('Playing piano');
} else if (canConduct) {
print('Waving hands');
} else {
print('Humming to self');
}
}
}
指定只有某些類(lèi)型可以使用的 Mixin - 比如绷杜, Mixin 可以調(diào)用 Mixin 自身沒(méi)有定義的方法 - 使用 on 來(lái)指定可以使用 Mixin 的父類(lèi)類(lèi)型:
mixin MusicalPerformer on Musician {
// ···
}
版本提示: mixin 關(guān)鍵字在 Dart 2.1 中被引用支持直秆。 早期版本中的代碼通常使用 abstract class 代替。 更多有關(guān) Mixin 在 2.1 中的變更信息鞭盟,請(qǐng)參見(jiàn) Dart SDK changelog 和 2.1 mixin specification 圾结。
提示: 對(duì) Mixin 的一些限制正在被移除。 關(guān)于更多詳情齿诉,參考 proposed mixin specification.
有關(guān) Dart 中 Mixin 的理論演變筝野,參考 A Brief History of Mixins in Dart.
Final Const
Final 和 Const
使用過(guò)程中從來(lái)不會(huì)被修改的變量晌姚, 可以使用 final 或 const, 而不是 var 或者其他類(lèi)型, Final 變量的值只能被設(shè)置一次遗座; Const 變量在編譯時(shí)就已經(jīng)固定 (Const 變量 是隱式 Final 的類(lèi)型.) 最高級(jí) final 變量或類(lèi)變量在第一次使用時(shí)被初始化舀凛。
提示: 實(shí)例變量可以是 final 類(lèi)型但不能是 const 類(lèi)型。 必須在構(gòu)造函數(shù)體執(zhí)行之前初始化 final 實(shí)例變量 —— 在變量聲明中途蒋,參數(shù)構(gòu)造函數(shù)中或構(gòu)造函數(shù)的初始化列表中進(jìn)行初始化。
創(chuàng)建和設(shè)置一個(gè) Final 變量:
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
final 不能被修改:
name = 'Alice'; // Error: 一個(gè) final 變量只能被設(shè)置一次馋记。
如果需要在編譯時(shí)就固定變量的值号坡,可以使用 const 類(lèi)型變量。 如果 Const 變量是類(lèi)級(jí)別的梯醒,需要標(biāo)記為 static const宽堆。 在這些地方可以使用在編譯時(shí)就已經(jīng)固定不變的值,字面量的數(shù)字和字符串茸习, 固定的變量畜隶,或者是用于計(jì)算的固定數(shù)字:
const bar = 1000000; // 壓力單位 (dynes/cm2)
const double atm = 1.01325 * bar; // 標(biāo)準(zhǔn)氣壓
Const 關(guān)鍵字不僅可以用于聲明常量變量。 還可以用來(lái)創(chuàng)建常量值号胚,以及聲明創(chuàng)建常量值的構(gòu)造函數(shù)籽慢。 任何變量都可以擁有常量值。
var foo = const [];
final bar = const [];
const baz = []; // Equivalent to `const []`
聲明 const 的初始化表達(dá)式中 const 可以被省略猫胁。 比如上面的 baz箱亿。 有關(guān)更多信息,參考 DON’T use const redundantly弃秆。
非 Final 届惋, 非 const 的變量是可以被修改的,即使這些變量 曾經(jīng)引用過(guò) const 值菠赚。
foo = [1, 2, 3]; // 曾經(jīng)引用過(guò) const [] 常量值脑豹。
Const 變量的值不可以修改:
baz = [42]; // Error: 常量變量不能賦值修改。
更多關(guān)于使用 const 創(chuàng)建常量值衡查,參考 Lists瘩欺, Maps, 和 Classes峡捡。
throw catch finnaly on rethrow
異常
Dart 代碼可以?huà)伋龊筒东@異常击碗。 異常表示一些未知的錯(cuò)誤情況。 如果異常沒(méi)有被捕獲们拙, 則異常會(huì)拋出稍途, 導(dǎo)致拋出異常的代碼終止執(zhí)行。
和 Java 有所不同砚婆, Dart 中的所有異常是非檢查異常械拍。 方法不會(huì)聲明它們拋出的異常突勇, 也不要求捕獲任何異常。
Dart 提供了 Exception 和 Error 類(lèi)型坷虑, 以及一些子類(lèi)型甲馋。 當(dāng)然也可以定義自己的異常類(lèi)型。 但是迄损,此外 Dart 程序可以?huà)伋鋈魏畏?null 對(duì)象定躏, 不僅限 Exception 和 Error 對(duì)象。
-
throw
下面是關(guān)于拋出或者 引發(fā) 異常的示例:throw FormatException('Expected at least 1 section');
也可以?huà)伋鋈我獾膶?duì)象:throw 'Out of llamas!';
提示: 高質(zhì)量的生產(chǎn)環(huán)境代碼通常會(huì)實(shí)現(xiàn) Error 或 Exception 類(lèi)型的異常拋出芹敌。因?yàn)閽伋霎惓J且粋€(gè)表達(dá)式痊远, 所以可以在 => 語(yǔ)句中使用,也可以在其他使用表達(dá)式的地方拋出異常:
void distanceTo(Point other) => throw UnimplementedError();
catch
捕獲異呈侠蹋可以避免異常繼續(xù)傳遞(除非重新拋出( rethrow )異常)碧聪。 可以通過(guò)捕獲異常的機(jī)會(huì)來(lái)處理該異常:try { breedMoreLlamas(); } on OutOfLlamasException { buyMoreLlamas(); }
通過(guò)指定多個(gè) catch 語(yǔ)句,可以處理可能拋出多種類(lèi)型異常的代碼液茎。 與拋出異常類(lèi)型匹配的第一個(gè) catch 語(yǔ)句處理異常逞姿。 如果 catch 語(yǔ)句未指定類(lèi)型, 則該語(yǔ)句可以處理任何類(lèi)型的拋出對(duì)象:
try { breedMoreLlamas(); } on OutOfLlamasException { // 一個(gè)特殊的異常 buyMoreLlamas(); } on Exception catch (e) { // 其他任何異常 print('Unknown exception: $e'); } catch (e) { // 沒(méi)有指定的類(lèi)型捆等,處理所有異常 print('Something really unknown: $e'); }
-
on catch
如上述代碼所示滞造,捕獲語(yǔ)句中可以同時(shí)使用 on 和 catch ,也可以單獨(dú)分開(kāi)使用楚里。 使用 on 來(lái)指定異常類(lèi)型断部, 使用 catch 來(lái) 捕獲異常對(duì)象。
catch() 函數(shù)可以指定1到2個(gè)參數(shù)班缎, 第一個(gè)參數(shù)為拋出的異常對(duì)象蝴光, 第二個(gè)為堆棧信息 ( 一個(gè) StackTrace 對(duì)象 )。
try { // ··· } on Exception catch (e) { print('Exception details:\n $e'); } catch (e, s) { print('Exception details:\n $e'); print('Stack trace:\n $s'); }
-
rethrow
如果僅需要部分處理異常达址, 那么可以使用關(guān)鍵字 rethrow 將異常重新拋出蔑祟。void misbehave() { try { dynamic foo = true; print(foo++); // Runtime error } catch (e) { print('misbehave() partially handled ${e.runtimeType}.'); rethrow; // Allow callers to see the exception. } } void main() { try { misbehave(); } catch (e) { print('main() finished handling ${e.runtimeType}.'); } }
-
finally
不管是否拋出異常, finally 中的代碼都會(huì)被執(zhí)行沉唠。 如果 catch 沒(méi)有匹配到異常疆虚, 異常會(huì)在 finally 執(zhí)行完成后,再次被拋出:try { breedMoreLlamas(); } finally { // Always clean up, even if an exception is thrown. cleanLlamaStalls(); }
任何匹配的 catch 執(zhí)行完成后满葛,再執(zhí)行 finally :
try { breedMoreLlamas(); } catch (e) { print('Error: $e'); // Handle the exception first. } finally { cleanLlamaStalls(); // Then clean up. }
更多詳情径簿,請(qǐng)參考 Exceptions 章節(jié)。
Typedefs
在 Dart 中嘀韧,函數(shù)也是對(duì)象篇亭,就想字符和數(shù)字對(duì)象一樣。 使用 typedef 锄贷,或者 function-type alias 為函數(shù)起一個(gè)別名译蒂, 別名可以用來(lái)聲明字段及返回值類(lèi)型曼月。 當(dāng)函數(shù)類(lèi)型分配給變量時(shí),typedef會(huì)保留類(lèi)型信息柔昼。
請(qǐng)考慮以下代碼哑芹,代碼中未使用 typedef :
class SortedCollection {
Function compare;
SortedCollection(int f(Object a, Object b)) {
compare = f;
}
}
// Initial, broken implementation. // broken ?
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
// 雖然知道 compare 是函數(shù)捕透,
// 但是函數(shù)是什么類(lèi)型 聪姿?
assert(coll.compare is Function);
}
當(dāng)把 f 賦值給 compare 的時(shí)候,類(lèi)型信息丟失了乙嘀。 f 的類(lèi)型是 (Object, Object) → int (這里 → 代表返回值類(lèi)型)咳燕, 但是 compare 得到的類(lèi)型是 Function 。如果我們使用顯式的名字并保留類(lèi)型信息乒躺, 這樣開(kāi)發(fā)者和工具都可以使用這些信息:
typedef Compare = int Function(Object a, Object b);
class SortedCollection {
Compare compare;
SortedCollection(this.compare);
}
// Initial, broken implementation.
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
assert(coll.compare is Function);
assert(coll.compare is Compare);
}
提示: 目前,typedefs 只能使用在函數(shù)類(lèi)型上低缩, 我們希望將來(lái)這種情況有所改變嘉冒。
由于 typedefs 只是別名, 他們還提供了一種方式來(lái)判斷任意函數(shù)的類(lèi)型咆繁。例如:
typedef Compare<T> = int Function(T a, T b);
int sort(int a, int b) => a - b;
void main() {
assert(sort is Compare<int>); // True!
}
Function
Dart 是一門(mén)真正面向?qū)ο蟮恼Z(yǔ)言讳推, 甚至其中的函數(shù)也是對(duì)象,并且有它的類(lèi)型 Function 玩般。 這也意味著函數(shù)可以被賦值給變量或者作為參數(shù)傳遞給其他函數(shù)银觅。 也可以把 Dart 類(lèi)的實(shí)例當(dāng)做方法來(lái)調(diào)用。 有關(guān)更多信息坏为,參考 Callable classes.
Deferred
延遲加載庫(kù)
Deferred loading (也稱(chēng)之為 lazy loading) 可以讓?xiě)?yīng)用在需要的時(shí)候再加載庫(kù)究驴。 下面是一些使用延遲加載庫(kù)的場(chǎng)景:
減少 APP 的啟動(dòng)時(shí)間。
執(zhí)行 A/B 測(cè)試匀伏,例如 嘗試各種算法的 不同實(shí)現(xiàn)洒忧。
加載很少使用的功能,例如可選的屏幕和對(duì)話(huà)框够颠。
要延遲加載一個(gè)庫(kù)熙侍,需要先使用 deferred as 來(lái)導(dǎo)入:
import 'package:greetings/hello.dart' deferred as hello;
當(dāng)需要使用的時(shí)候,使用庫(kù)標(biāo)識(shí)符調(diào)用 loadLibrary() 函數(shù)來(lái)加載庫(kù):
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
在前面的代碼履磨,使用 await 關(guān)鍵字暫停代碼執(zhí)行一直到庫(kù)加載完成蛉抓。 關(guān)于 async 和 await 的更多信息請(qǐng)參考 異步支持。
在一個(gè)庫(kù)上你可以多次調(diào)用 loadLibrary() 函數(shù)剃诅。但是該庫(kù)只是載入一次巷送。
使用延遲加載庫(kù)的時(shí)候,請(qǐng)注意一下問(wèn)題:
延遲加載庫(kù)的常量在導(dǎo)入的時(shí)候是不可用的综苔。 只有當(dāng)庫(kù)加載完畢的時(shí)候惩系,庫(kù)中常量才可以使用位岔。
在導(dǎo)入文件的時(shí)候無(wú)法使用延遲庫(kù)中的類(lèi)型。 如果你需要使用類(lèi)型堡牡,則考慮把接口類(lèi)型移動(dòng)到另外一個(gè)庫(kù)中抒抬, 讓兩個(gè)庫(kù)都分別導(dǎo)入這個(gè)接口庫(kù)。
Dart 隱含的把 loadLibrary() 函數(shù)導(dǎo)入到使用 deferred as 的命名空間 中晤柄。 loadLibrary() 方法返回一個(gè) Future擦剑。
變量類(lèi)型
Dart 語(yǔ)言支持以下內(nèi)建類(lèi)型:
- Number
- String
- Boolean
- List (也被稱(chēng)為 Array)
- Map
- Set
- Rune (用于在字符串中表示 Unicode 字符)
- Symbol
這些類(lèi)型都可以被初始化為字面量。 例如, 'this is a string' 是一個(gè)字符串的字面量芥颈, true 是一個(gè)布爾的字面量惠勒。
因?yàn)樵?Dart 所有的變量終究是一個(gè)對(duì)象(一個(gè)類(lèi)的實(shí)例), 所以變量可以使用 構(gòu)造函數(shù) 進(jìn)行初始化爬坑。 一些內(nèi)建類(lèi)型擁有自己的構(gòu)造函數(shù)纠屋。 例如, 通過(guò) Map() 來(lái)構(gòu)造一個(gè) map 變量盾计。
-
Number
Dart 語(yǔ)言的 Number 有兩種類(lèi)型:
-
int
整數(shù)值不大于64位售担, 具體取決于平臺(tái)。 在 Dart VM 上署辉, 值的范圍從 -263 到 263 - 1. Dart 被編譯為 JavaScript 時(shí)族铆,使用 JavaScript numbers, 值的范圍從 -253 到 253 - 1.
-
double
64位(雙精度)浮點(diǎn)數(shù),依據(jù) IEEE 754 標(biāo)準(zhǔn)哭尝。
int 和 double 都是 num. 的亞類(lèi)型哥攘。 num 類(lèi)型包括基本運(yùn)算 +, -材鹦, /逝淹, 和 *, 以及 abs()侠姑, ceil()巫湘, 和 floor()旦万, 等函數(shù)方法田晚。 (按位運(yùn)算符稀余,例如?,定義在 int 類(lèi)中安吁。) 如果 num 及其亞類(lèi)型找不到你想要的方法醉蚁, 嘗試查找使用 dart:math 庫(kù)。
整數(shù)類(lèi)型不包含小數(shù)點(diǎn)鬼店。 下面是定義整數(shù)類(lèi)型字面量的例子:
var x = 1; var hex = 0xDEADBEEF;
如果一個(gè)數(shù)字包含小數(shù)點(diǎn)网棍,那么就是小數(shù)類(lèi)型。 下面是定義小數(shù)類(lèi)型字面量的例子:
var y = 1.1; var exponents = 1.42e5;
從 Dart 2.1 開(kāi)始妇智,必要的時(shí)候 int 字面量會(huì)自動(dòng)轉(zhuǎn)換成 double 類(lèi)型滥玷。
double z = 1; // 相當(dāng)于 double z = 1.0.
版本提示: 在 2.1 之前氏身,在 double 上下文中使用 int 字面量是錯(cuò)誤的。
以下是將字符串轉(zhuǎn)換為數(shù)字的方法惑畴,反之亦然:
// 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');
int 特有的傳統(tǒng)按位運(yùn)算操作蛋欣,移位(<<, >>)如贷,按位與(&)以及 按位或(|)陷虎。 例如:
assert((3 << 1) == 6); // 0011 << 1 == 0110 assert((3 >> 1) == 1); // 0011 >> 1 == 0001 assert((3 | 4) == 7); // 0011 | 0100 == 0111
數(shù)字類(lèi)型字面量是編譯時(shí)常量。 在算術(shù)表達(dá)式中杠袱,只要參與計(jì)算的因子是編譯時(shí)常量尚猿, 那么算術(shù)表達(dá)式的結(jié)果也是編譯時(shí)常量。
const msPerSecond = 1000; const secondsUntilRetry = 5; const msUntilRetry = secondsUntilRetry * msPerSecond;
-
-
String
Dart 字符串是一組 UTF-16 單元序列楣富。 字符串通過(guò)單引號(hào)或者雙引號(hào)創(chuàng)建凿掂。
var s1 = 'Single quotes work well for string literals.'; var s2 = "Double quotes work just as well."; var s3 = 'It\'s easy to escape the string delimiter.'; var s4 = "It's even easier to use the other delimiter.";
字符串可以通過(guò) ${expression} 的方式內(nèi)嵌表達(dá)式。 如果表達(dá)式是一個(gè)標(biāo)識(shí)符纹蝴,則 {} 可以省略缠劝。 在 Dart 中通過(guò)調(diào)用就對(duì)象的 toString() 方法來(lái)得到對(duì)象相應(yīng)的字符串。
var s = 'string interpolation'; assert('Dart has $s, which is very handy.' == 'Dart has string interpolation, ' + 'which is very handy.'); assert('That deserves all caps. ' + '${s.toUpperCase()} is very handy!' == 'That deserves all caps. ' + 'STRING INTERPOLATION is very handy!');
提示: == 運(yùn)算符用來(lái)測(cè)試兩個(gè)對(duì)象是否相等骗灶。 在字符串中,如果兩個(gè)字符串包含了相同的編碼序列秉馏,那么這兩個(gè)字符串相等耙旦。 units.
可以使用 + 運(yùn)算符來(lái)把多個(gè)字符串連接為一個(gè),也可以把多個(gè)字面量字符串寫(xiě)在一起來(lái)實(shí)現(xiàn)字符串連接:
var s1 = 'String ' 'concatenation' " works even over line breaks."; assert(s1 == 'String concatenation works even over ' 'line breaks.'); var s2 = 'The + operator ' + 'works, as well.'; assert(s2 == 'The + operator works, as well.');
使用連續(xù)三個(gè)單引號(hào)或者三個(gè)雙引號(hào)實(shí)現(xiàn)多行字符串對(duì)象的創(chuàng)建:
var s1 = ''' You can create multi-line strings like this one. '''; var s2 = """This is also a multi-line string.""";
使用 r 前綴萝究,可以創(chuàng)建 “原始 raw” 字符串:
var s = r"In a raw string, even \n isn't special.";
參考 Runes 來(lái)了解如何在字符串中表達(dá) Unicode 字符免都。
一個(gè)編譯時(shí)常量的字面量字符串中,如果存在插值表達(dá)式帆竹,表達(dá)式內(nèi)容也是編譯時(shí)常量绕娘, 那么該字符串依舊是編譯時(shí)常量。 插入的常量值類(lèi)型可以是 null栽连,數(shù)值险领,字符串或布爾值。
// const 類(lèi)型數(shù)據(jù) const aConstNum = 0; const aConstBool = true; const aConstString = 'a constant string'; // 非 const 類(lèi)型數(shù)據(jù) var aNum = 0; var aBool = true; var aString = 'a string'; const aConstList = [1, 2, 3]; const validConstString = '$aConstNum $aConstBool $aConstString'; //const 類(lèi)型數(shù)據(jù) // const invalidConstString = '$aNum $aBool $aString $aConstList'; //非 const 類(lèi)型數(shù)據(jù)
更多關(guān)于 string 的使用, 參考 字符串和正則表達(dá)式.
-
Boolean
Dart 使用 bool 類(lèi)型表示布爾值秒紧。 Dart 只有字面量 true and false 是布爾類(lèi)型绢陌, 這兩個(gè)對(duì)象都是編譯時(shí)常量。Dart 的類(lèi)型安全意味著不能使用 if (nonbooleanValue) 或者 assert (nonbooleanValue)熔恢。 而是應(yīng)該像下面這樣脐湾,明確的進(jìn)行值檢查:
// 檢查空字符串。 var fullName = ''; assert(fullName.isEmpty); // 檢查 0 值叙淌。 var hitPoints = 0; assert(hitPoints <= 0); // 檢查 null 值秤掌。 var unicorn; assert(unicorn == null); // 檢查 NaN 愁铺。 var iMeantToDoThis = 0 / 0; assert(iMeantToDoThis.isNaN);
-
-
List
幾乎每種編程語(yǔ)言中最常見(jiàn)的集合可能是 array 或有序的對(duì)象集合。 在 Dart 中的 Array 就是 List 對(duì)象闻鉴, 通常稱(chēng)之為 List 茵乱。Dart 中的 List 字面量非常像 JavaScript 中的 array 字面量。 下面是一個(gè) Dart List 的示例:
var list = [1, 2, 3];
提示: Dart 推斷 list 的類(lèi)型為 List<int> 椒拗。 如果嘗試將非整數(shù)對(duì)象添加到此 List 中似将, 則分析器或運(yùn)行時(shí)會(huì)引發(fā)錯(cuò)誤。 有關(guān)更多信息蚀苛,請(qǐng)閱讀 類(lèi)型推斷在验。
Lists 的下標(biāo)索引從 0 開(kāi)始,第一個(gè)元素的索引是 0堵未。 list.length - 1 是最后一個(gè)元素的索引腋舌。 訪(fǎng)問(wèn) List 的長(zhǎng)度和元素與 JavaScript 中的用法一樣:
var list = [1, 2, 3]; assert(list.length == 3); assert(list[1] == 2); list[1] = 1; assert(list[1] == 1);
在 List 字面量之前添加 const 關(guān)鍵字,可以定義 List 類(lèi)型的編譯時(shí)常量:
var constantList = const [1, 2, 3]; // constantList[1] = 1; // 取消注釋會(huì)引起錯(cuò)誤渗蟹。
List 類(lèi)型包含了很多 List 的操作函數(shù)块饺。 更多信息參考 泛型 和 集合.
-
Set
在 Dart 中 Set 是一個(gè)元素唯一且無(wú)需的集合。 Dart 為 Set 提供了 Set 字面量和 Set 類(lèi)型雌芽。版本提示: 雖然 Set 類(lèi)型 一直是 Dart 的核心部分授艰, 但在 Dart2.2 中才引入了 Set 字面量 。
下面是通過(guò)字面量創(chuàng)建 Set 的一個(gè)簡(jiǎn)單示例:
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Note: Dart 推斷 halogens 類(lèi)型為 Set<String> 世落。如果嘗試為它添加一個(gè) 錯(cuò)誤類(lèi)型的值淮腾,分析器或執(zhí)行時(shí)會(huì)拋出錯(cuò)誤。更多內(nèi)容屉佳,參閱 類(lèi)型推斷谷朝。
要?jiǎng)?chuàng)建一個(gè)空集,使用前面帶有類(lèi)型參數(shù)的 {} 武花,或者將 {} 賦值給 Set 類(lèi)型的變量:
var names = <String>{}; // Set<String> names = {}; // 這樣也是可以的圆凰。 // var names = {}; // 這樣會(huì)創(chuàng)建一個(gè) Map ,而不是 Set 体箕。
是 Set 還是 Map 专钉? Map 字面量語(yǔ)法同 Set 字面量語(yǔ)法非常相似。 因?yàn)橄扔械?Map 字母量語(yǔ)法累铅,所以 {} 默認(rèn)是 Map 類(lèi)型驶沼。 如果忘記在 {} 上注釋類(lèi)型或賦值到一個(gè)未聲明類(lèi)型的變量上, 那么 Dart 會(huì)創(chuàng)建一個(gè)類(lèi)型為 Map<dynamic, dynamic> 的對(duì)象争群。
使用 add() 或 addAll() 為已有的 Set 添加元素:
var elements = <String>{}; elements.add('fluorine'); elements.addAll(halogens);
使用 .length 來(lái)獲取 Set 中元素的個(gè)數(shù):
var elements = <String>{}; elements.add('fluorine'); elements.addAll(halogens); assert(elements.length == 5);
在 Set 字面量前增加 const 回怜,來(lái)創(chuàng)建一個(gè)編譯時(shí) Set 常量:
final constantSet = const { 'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine', }; // constantSet.add('helium'); // Uncommenting this causes an error.
更多關(guān)于 Set 的內(nèi)容,參閱 Generic 及 Set。
-
Map
通常來(lái)說(shuō)玉雾, Map 是用來(lái)關(guān)聯(lián) keys 和 values 的對(duì)象翔试。 keys 和 values 可以是任何類(lèi)型的對(duì)象。在一個(gè) Map 對(duì)象中一個(gè) key 只能出現(xiàn)一次复旬。 但是 value 可以出現(xiàn)多次垦缅。 Dart 中 Map 通過(guò) Map 字面量 和 Map 類(lèi)型來(lái)實(shí)現(xiàn)。下面是使用 Map 字面量的兩個(gè)簡(jiǎn)單例子:
var gifts = { // Key: Value 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' }; var nobleGases = { 2: 'helium', 10: 'neon', 18: 'argon', };
提示: Dart 會(huì)將 gifts 的類(lèi)型推斷為 Map<String, String>驹碍, nobleGases 的類(lèi)型推斷為 Map<int, String> 壁涎。 如果嘗試在上面的 map 中添加錯(cuò)誤類(lèi)型,那么分析器或者運(yùn)行時(shí)會(huì)引發(fā)錯(cuò)誤志秃。 有關(guān)更多信息怔球,請(qǐng)閱讀類(lèi)型推斷。浮还。
以上 Map 對(duì)象也可以使用 Map 構(gòu)造函數(shù)創(chuàng)建:
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()。 因?yàn)樵?Dart 2 中钧舌,new 關(guān)鍵字是可選的担汤。 有關(guān)更多信息,參考 構(gòu)造函數(shù)的使用洼冻。
類(lèi)似 JavaScript 崭歧,添加 key-value 對(duì)到已有的 Map 中:
var gifts = {'first': 'partridge'}; gifts['fourth'] = 'calling birds'; // Add a key-value pair
類(lèi)似 JavaScript ,從一個(gè) Map 中獲取一個(gè) value:
var gifts = {'first': 'partridge'}; assert(gifts['first'] == 'partridge');
如果 Map 中不包含所要查找的 key撞牢,那么 Map 返回 null:
var gifts = {'first': 'partridge'}; assert(gifts['fifth'] == null);
使用 .length 函數(shù)獲取當(dāng)前 Map 中的 key-value 對(duì)數(shù)量:
var gifts = {'first': 'partridge'}; gifts['fourth'] = 'calling birds'; assert(gifts.length == 2);
創(chuàng)建 Map 類(lèi)型運(yùn)行時(shí)常量驾荣,要在 Map 字面量前加上關(guān)鍵字 const。
final constantMap = const { 2: 'helium', 10: 'neon', 18: 'argon', }; // constantMap[2] = 'Helium'; // 取消注釋會(huì)引起錯(cuò)誤普泡。
更名多關(guān)于 Map 的內(nèi)容,參考 Generics and Maps.
-
Rune
在 Dart 中审编, Rune 用來(lái)表示字符串中的 UTF-32 編碼字符撼班。Unicode 定義了一個(gè)全球的書(shū)寫(xiě)系統(tǒng)編碼, 系統(tǒng)中使用的所有字母垒酬,數(shù)字和符號(hào)都對(duì)應(yīng)唯一的數(shù)值編碼砰嘁。 由于 Dart 字符串是一系列 UTF-16 編碼單元, 因此要在字符串中表示32位 Unicode 值需要特殊語(yǔ)法支持勘究。
表示 Unicode 編碼的常用方法是矮湘, \uXXXX, 這里 XXXX 是一個(gè)4位的16進(jìn)制數(shù)。 例如口糕,心形符號(hào) (?) 是 \u2665缅阳。 對(duì)于特殊的非 4 個(gè)數(shù)值的情況, 把編碼值放到大括號(hào)中即可景描。 例如十办,emoji 的笑臉 (?) 是 \u{1f600}秀撇。
String 類(lèi)有一些屬性可以獲得 rune 數(shù)據(jù)。 屬性 codeUnitAt 和 codeUnit 返回16位編碼數(shù)據(jù)向族。 屬性 runes 獲取字符串中的 Rune 呵燕。
######提示: 謹(jǐn)慎使用 list 方式操作 Rune 。 這種方法很容易引發(fā)崩潰件相, 具體原因取決于特定的語(yǔ)言再扭,字符集和操作。 有關(guān)更多信息夜矗,參考 How do I reverse a String in Dart? on Stack Overflow.
-
Symbol
一個(gè) Symbol 對(duì)象表示 Dart 程序中聲明的運(yùn)算符或者標(biāo)識(shí)符泛范。 你也許永遠(yuǎn)都不需要使用 Symbol ,但要按名稱(chēng)引用標(biāo)識(shí)符的 API 時(shí)侯养, Symbol 就非常有用了敦跌。 因?yàn)榇a壓縮后會(huì)改變標(biāo)識(shí)符的名稱(chēng),但不會(huì)改變標(biāo)識(shí)符的符號(hào)逛揩。 通過(guò)字面量 Symbol 柠傍,也就是標(biāo)識(shí)符前面添加一個(gè) # 號(hào),來(lái)獲取標(biāo)識(shí)符的 Symbol 辩稽。
#radix #bar
Symbol 字面量是編譯時(shí)常量惧笛。
控制流程語(yǔ)句
你可以通過(guò)下面任意一種方式來(lái)控制 Dart 程序流程:
if and else
for loops
while and do-while loops
break and continue
switch and case
assert
使用 try-catch 和 throw 也可以改變程序流程, 詳見(jiàn) Exceptions逞泄。