Flutter_一小時(shí)入門(mén)Dart

本文適合有代碼基礎(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í)行流程如下:

    1. 等待涝婉,直到流發(fā)出一個(gè)值哥力。
    2. 執(zhí)行 for 循環(huán)體,將變量設(shè)置為該發(fā)出的值
    3. 重復(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)型:

  1. Number
  2. String
  3. Boolean
  4. List (也被稱(chēng)為 Array)
  5. Map
  6. Set
  7. Rune (用于在字符串中表示 Unicode 字符)
  8. 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逞泄。

文章節(jié)選總結(jié)自來(lái)源

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末患整,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子喷众,更是在濱河造成了極大的恐慌各谚,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件到千,死亡現(xiàn)場(chǎng)離奇詭異昌渤,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)憔四,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)膀息,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人了赵,你說(shuō)我怎么就攤上這事潜支。” “怎么了柿汛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵冗酿,是天一觀(guān)的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)已烤,這世上最難降的妖魔是什么鸠窗? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮胯究,結(jié)果婚禮上稍计,老公的妹妹穿的比我還像新娘。我一直安慰自己裕循,他們只是感情好臣嚣,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著剥哑,像睡著了一般硅则。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上株婴,一...
    開(kāi)封第一講書(shū)人閱讀 52,713評(píng)論 1 312
  • 那天怎虫,我揣著相機(jī)與錄音,去河邊找鬼困介。 笑死大审,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的座哩。 我是一名探鬼主播徒扶,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼根穷!你這毒婦竟也來(lái)了姜骡?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤屿良,失蹤者是張志新(化名)和其女友劉穎圈澈,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體尘惧,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡康栈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了褥伴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漾狼,死狀恐怖重慢,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情逊躁,我是刑警寧澤似踱,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響核芽,放射性物質(zhì)發(fā)生泄漏囚戚。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一轧简、第九天 我趴在偏房一處隱蔽的房頂上張望驰坊。 院中可真熱鬧,春花似錦哮独、人聲如沸拳芙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)舟扎。三九已至,卻和暖如春悴务,著一層夾襖步出監(jiān)牢的瞬間睹限,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工讯檐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留羡疗,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓裂垦,卻偏偏與公主長(zhǎng)得像顺囊,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蕉拢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容