Dart 2官方文檔中文版(Dart 編程語言導覽)Part 1

導覽

Dart編程語言導覽

本文展示如何使用各個主要Dart功能朴皆,從變量所踊、運算符到類和庫拥坛,這里假定你已經至少了解如何使用一種其它編程語言缀蹄。

要了解更多有關 Dart核心庫的知識,請參見核心庫導覽排拷。在想要了解更多有關語言功能的時候侧漓,請查詢Dart語言規(guī)范

小貼士: 你可以借助DartPad來使用Dart語言的大部分功能 (了解更多)攻泼。

打開DartPad

一個Dart基礎程序

以下代碼使用了Dart的大量最基礎的功能:

// 定義一個函數

printInteger(int  aNumber)  {

  print('The number is $aNumber.');  // 打印到控制臺

}

// 這是應用開始執(zhí)行的地方火架。

main()  {

  var  number  =  42;  // 聲明和初始化一個變量

  printInteger(number);  // 調用函數

}

以下是這個程序所使用到的可用于所有(或幾乎所有)的Dart應用的部分:

// 這是一條注釋

單行注釋。Dart還支持多行注釋和文件注釋忙菠。更多詳情何鸡,請參見 注釋.

int

一種類型。其它的一些 內置類型String, Listbool牛欢。

42>

一個數字字面量骡男。數字字面量是一種編譯時常量。

print()

一種顯示輸出的方便的方式傍睹。

'...' (or "...")

一個字符串字面量隔盛。

$*variableName* (或 ${*expression*})

插值字符串:包含等價于字符串字面量的變量或表達式的字符串犹菱。更多相關信息,請參見 字符串.

main()

在應用執(zhí)行開始處的特殊的吮炕、必須的頂級函數腊脱。更多相關信息,請參見 main()函數.

var

一種無需指定類型聲明變量的方式龙亲。

Note: 本站的代碼遵循 Dart 樣式指南中的準則陕凹。

重要概念

在學習Dart編程語言的過程中,請在心中保持以下事實和概念:

  • 在變量中放置的所有內容都是對象鳄炉,并且每個對象都是一個類的實例杜耙。包括數字、函數和 null 都是對象拂盯。所有的對象都繼承自 Object 類佑女。
  • 雖然Dart是強類型語言,類型標注卻是可選的谈竿,因為Dart可以推導類型团驱。在以上的代碼中, number 所推導的類型是 int榕订。在你想要顯式地說明無需設定類型店茶, 使用特殊類型 dynamic.
  • Dart支持泛型,如 List<int> (整型列表) 或 List<dynamic> (任意類型對象的列表)劫恒。
  • Dart支持頂級函數(如 main())贩幻,以及與類或對象綁定的函數 (分別為靜態(tài)和實例方法)。你也可以在函數內創(chuàng)建函數(嵌套或局部函數)两嘴。
  • 類型地丛楚,Dart支持頂級變量,以及與類或對象綁定的變量(靜態(tài)和實例變量)憔辫。實例變量有時也稱為字段或屬性趣些。
  • 不同于Java,Dart沒有public, protectedprivate這些關鍵字贰您。 如果一個標識符以下劃線(_)開頭坏平,它是對庫私有的。詳情請參見 庫和可見性.
  • 標識符可以字母或下劃線 (_)開頭锦亦,后接這些字符和數字的任意組合舶替。
  • Dart既有表達式(擁有運行時值)也有語句(沒有運行時值)。例如杠园, 條件表達式 condition ? expr1 : expr2 有一個值expr1expr2顾瞪。對比 if-else 語句則沒有值。一條語句通常包含一個或多個表達式,但一個表達式不能直接包含一條語句陈醒。
  • Dart工具可以報出兩類問題:警告(warning)和錯誤(error) 惕橙。警告只是表明你的代碼可能無法運行,但并不會阻止程序的執(zhí)行钉跷。錯誤可以是編譯時或運行時的弥鹦。編譯時錯誤會完全阻止代碼的執(zhí)行,運行時錯誤會在代碼執(zhí)行時導致 異常 的拋出爷辙。

關鍵字

下表中列出了Dart編程語言中具有特殊含義的單詞惶凝。

| abstract 2 | 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 |

避免使用這些詞作為標識符。但是在必要時標記有上標文本的關鍵字可作為標識符:

  • 上標為 1 的詞為上下文關鍵字犬钢,僅在指定位置具有含義。它們在任何地方都是有效的標識符思灰。
  • 上標為 2 的詞是內置標識符玷犹。為簡化將JavaScript代碼移植到Dart的任務,這些關鍵字在大部分地方是有效的關鍵字洒疚,但不能用于類或類型名稱,或者是作為導入的前綴。
  • 上標為 3 的詞是在Dart 1.0版本之后添加的與異步支持相關的更新的抓韩、有限的保留詞肴捉。你無法使用async, async*sync*標記的函數體內使用 awaityield 作為標識符。

表中的其它詞都是保留詞乏德,無法用作標識符撤奸。

變量

以下是一個創(chuàng)建變量并初始化的示例:

var  name  =  'Bob';

變量存儲引用。名為name的變量包含一個對值為”Bob”的String對象的引用喊括。

變量name的類型推導為String胧瓜,但你可以通過指定類型來進行修改。如果對象不僅限于單個類型郑什,按照設計指南將其指定為Objectdynamic類型府喳。

dynamic name  =  'Bob';

另一個選項是顯式地將其聲明為所要推導的類型:

String  name  =  'Bob';

Note: 本頁中對局部變量按照 樣式指南推薦 使用 var,而非類型注解蘑拯。

默認值

未初始過的值有一個初始值null钝满。即使是帶有數值類型的變量初始值也是null,因為數值類型和Dart中的所有內容一樣申窘,都是對象弯蚜。

int  lineCount;

assert(lineCount  ==  null);

Note: 生產代碼會忽略 assert() 調用。而在開發(fā)期間偶洋,當 if 條件為假時 assert(*condition*) 會拋出一個異常熟吏。詳情請參見 Assert

Final和const

如果你不想要修改一個變量,使用 finalconst來替代 var 或加前類型前牵寺。final變量只能設置一次悍引,const變量是編譯時常量。(const變量是隱式的final)帽氓。final頂級或類變量在初次使用時進行初始化趣斤。

Note: 實例變量可以是 final ,但不能為 const黎休。final實例變量必須在構造函數體開始之前進行初始化浓领,通過構造函數參數在變量聲明中或在構造函數的初始化程序列表中。

以下是一個創(chuàng)建和設置final變量的示例:

final  name  =  'Bob';  // 無類型標注

final  String  nickname  =  'Bobby';

你無法修改final變量的值:


name  =  'Alice';  // Error: a final variable can only be set once.

對你希望是編譯時常量的變量使用const势腮。如果const變量是類級別的联贩,將其標記為 static const。在聲明變量之處捎拯,設置值為編譯時常量泪幌,如數值或字符串字面量、const變量或對常數的算術運算結果:

const  bar  =  1000000;  // 單位壓強 (dynes/cm2)

const  double  atm  =  1.01325  *  bar;  // 標準大氣

const 關鍵字不只是為聲明常變量的署照。你還可以使用它來創(chuàng)建常量值祸泪,以及聲明創(chuàng)建常量值的構造函數。任意變量可擁有常量值建芙。

var  foo  =  const  [];

final  bar  =  const  [];

const  baz  =  [];  // 等價于 const []

你可以在const聲明的初始化表達式中省略 const没隘,像上面的 baz 。詳情請參見 不要重復使用const.

你可以修改一個非final禁荸、非const變量的值右蒲,即使它曾經是一個const值:

foo  =  [1,  2,  3];  // 曾經是const []

但是不能修改const變量的值:


baz  =  [42];  // Error: Constant variables can't be assigned a value.

更多有關使用 const 創(chuàng)建常量值的內容,請參見 列表, 映射屡限。

內置類型

Dart語言擁有對如下類型的特別支持:

  • 數值
  • 字符串
  • 布爾型
  • 列表 (也稱為數組)
  • 映射
  • rune (用于在字符串表示Unicode字符串)
  • 符號

你可以使用字面量初始化任意這些特殊類型的對象品嚣。例如, 'this is a string' 是一個字符串字面量钧大, true 是一個布爾型字面量翰撑。

因為Dart中的每個變量都引用一個對象 – 一個類的實例,通嘲⊙耄可以使用構造函數來初始化變量眶诈。一些內置類型有它們自己的構造函數。例如瓜饥,你可以使用 Map() 構造函數來創(chuàng)建一個映射逝撬。

數值

Dart有兩種數值類型:

int

整型值根據平臺不大于64位。在 Dart VM中乓土,值可以為 -263 到 263 – 1宪潮。編譯為JavaScript的Dart使用 JavaScript數值溯警, 允許的值為 -253 到 253 – 1。

double

64位(雙精度)浮點數值狡相,如IEEE 754 標準中所描述梯轻。

intdoublenum的子類型。num類型包含基本運算符如 +, -, / 和 *尽棕,也包含其它方法中的 abs(),ceil()floor()喳挑。(位相關的運算符,如 >>滔悉,在 int 類中定義)伊诵。 如果num及其子類型中沒有你所要尋找的,可以使用 dart:math 庫回官。

整型是不包含小數點的數字曹宴。以下是一些定義整型字面量的示例:

var  x  =  1;

var  hex  =  0xDEADBEEF;

如果數值中包含小數點,則為double類型歉提。以下是一些定義double字面量的示例:


var  y  =  1.1;

var  exponents  =  1.42e5;

在 Dart 2.1中浙炼,整型字面在需要時會自動轉化為double值:

double  z  =  1;  // 等價于 z = 1.0.

Version note: 在Dart 2.1之前,在double上下文中使用整型字面量會報錯唯袄。

以下是如何將字符串轉化為數字及其反向操作:

// 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)的按鈕移動 (<<, >>)、與 (&)和 或 (|)運算符蜗帜。例如:


assert((3  <<  1)  ==  6);  // 0011 << 1 == 0110

assert((3  >>  1)  ==  1);  // 0011 >> 1 == 0001

assert((3  |  4)  ==  7);  // 0011 | 0100 == 0111

字面量數字是編譯時常量恋拷。很多算術表達式也是編譯時常量,只要它們的運算項是運算為數值的編譯時常量厅缺。

const  msPerSecond  =  1000;

const  secondsUntilRetry  =  5;

const  msUntilRetry  =  secondsUntilRetry *  msPerSecond;

字符串

Dart字符串是一個UTF-16代碼單元蔬顾。你可以使用單引號或雙引號來創(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.";

可以通過使用${expression}來將表達式的值放到字符串中。如果表達式是一個標識符湘捎,可以省略{}诀豁。要獲取一個對象對應的字符串,Dart中調用對象的toString()方法窥妇。

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!');

Note: == 運算符用于測試兩個對象是否相等舷胜。如果兩個字符串擁有相同序列的代碼單元則相等。

可以使用相鄰字符串字面量或者了 + 運算符來拼接字符串:

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.');

另一種創(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)建“原生”字符串:

var  s  =  r'In a raw string, not even \n gets special treatment.';

參見 Rune 來獲取如何在字符串中表達Unicode字符的詳情活翩。

字符串字面量是編譯時常量烹骨,僅需編譯時常量中的插值表達式運行結果為null或數值、字符串或布爾值材泄。

// 這些可以在一個const字符串中使用

const  aConstNum  =  0;

const  aConstBool  =  true;

const  aConstString  =  'a constant string';

// 這些不可以在一個const字符串中使用

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';

更多有關使用字符串的信息沮焕,參見 字符串和正則表達式

布爾型

要表現布爾值拉宗,Dart中有一個名為bool的類型峦树。僅有兩個對象的類型為bool:布爾型字面量truefalse辣辫,它們都是編譯時常量。

Dart的類型安全意味著你不能使用if (*nonbooleanValue*)assert (*nonbooleanValue*)這樣的代碼魁巩。而是要顯式的檢查值急灭,類似這樣:

// 檢查空字符串

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);

列表

或許在幾乎所有編程語言中最常見的集合(collection)都是數組,或有序的對象組歪赢。在Dart化戳,數組是List對象,因此大部分會稱其為列表埋凯。

Dart的列表字面量和JavaScript中的數組字面量很像点楼。以下是一個簡單的Dart列表:

var  list  =  [1,  2,  3];

Note: Dart推導 list 的類型為 List<int>。如果你嘗試向這個列表中添加非整型對象白对,分析器或運行時會拋出錯誤掠廓。更多信息請閱讀 類型推導

列表使用基于0的索引甩恼,即0是第1個元素的索引蟀瞧,并且 list.length - 1 是最后一個元素的索引。你可以完全像JavaScript中那樣獲取一個列表的長度并引用列表元素:

var  list  =  [1,  2,  3];

assert(list.length  ==  3);

assert(list[1]  ==  2);

list[1]  =  1;

assert(list[1]  ==  1);

要創(chuàng)建一個為運行是常量的列表条摸,在列表字面量之前添加 const


var  constantList  =  const  [1,  2,  3];

// constantList[1] = 1; // 取消這行的注釋會導致報錯

Dart 2.3 引入了展開運算符(...) 及判空展開運算符 (...?)悦污,提供一種向集合插入多個元素的簡潔方式。

例如钉蒲,你可以使用展開運算符 (...) 來將列表中的所有元素插入到另一個列表中:


var  list  =  [1,  2,  3];

var  list2  =  [0,  ...list];

assert(list2.length  ==  4);

如果展開運算符右側的表達式有可能為null切端,可通過使用可判空展開運算符(...?)來避免異常:

var  list;

var  list2  =  [0,  ...?list];

assert(list2.length  ==  1);

更多有關使用展開運算符的詳情和示例,參見展開運算符提議顷啼。

Dart 2.3 還引入了collection ifcollection for踏枣,可以使用條件(if)和循環(huán) (for)來構建使用條件(if)和循環(huán) (for)的集合。

以下是使用collection if來創(chuàng)建一個包含3項或4項的列表::

var  nav  =  [

  'Home',

  'Furniture',

  'Plants',

  if  (promoActive)  'Outlet'

];

以下是使用collection for來在將它們添加到另一個列表之前操作列表項的示例:


var  listOfInts  =  [1,  2,  3];

var  listOfStrings  =  [

  '#0',

  for  (var  i  in  listOfInts)  '#$i'

];

assert(listOfStrings[1]  ==  '#1');

更多有關使用collection if和for的示例钙蒙,參見 控制流collection建議茵瀑。

列表類型有很多操作列表的便捷的方法。有關列表更多的信息躬厌,請參見泛型集合.

Dart中的集(set)是一個包含獨立項的無序集合马昨。Dart對集的支持由集字面量和Set類型所提供。

Version note: 雖然Set類型一直是Dart的核心部分扛施,集字面量在Dart 2.2中才引入偏陪。

以下是一個簡單的Dart集,使用集字面量創(chuàng)建:


var  halogens  =  {'fluorine',  'chlorine',  'bromine',  'iodine',  'astatine'};

Note: Dart推導 halogens 的類型為 Set<String>煮嫌。 如果你嘗試向集添加錯誤類型的值笛谦,分析器或運行時會拋出錯誤。更多信息昌阿,請閱讀類型推導部分饥脑。

要創(chuàng)建空集恳邀,使用帶有類型前綴的{}或向類型為Set的變量賦值{}


var  names  =  <String>{};

// Set<String> names = {}; // 這也同樣起作用

// var names = {}; // 創(chuàng)建一個映射,而非集

集或映射? 映射字面量的語法類型集字面量灶轰。因為映射字面量的優(yōu)先級更高谣沸, {} 的默認為 Map 類型。如果你忘記對 {} 進行類型標注笋颤,或者它所賦值的變量乳附,那么Dart會創(chuàng)建一個類型為 Map<dynamic, dynamic>的對象。

使用add()addAll() 方法向已有集添加子項:


var  elements  =  <String>{};

elements.add('fluorine');

elements.addAll(halogens);

使用 .length 來獲取集中子項的數量:


var  elements  =  <String>{};

elements.add('fluorine');

elements.addAll(halogens);

assert(elements.length  ==  5);

創(chuàng)建為運行時常量的集伴澄,在集字面量前添加const


final  constantSet  =  const  {

  'fluorine',

  'chlorine',

  'bromine',

  'iodine',

  'astatine',

};

// constantSet.add('helium'); // 取消本行注釋會導致報錯

在Dart 2.3中赋除,集也像列表一樣支持展開運算符 (......?) 以及 collection if 和 for。更多信息非凌,參見 列表展開運算符列表集合運算符 部分的討論举农。

有關集的更多知識,請參見 泛型.

映射

總的來說敞嗡,映射是一個關聯鍵和值的對象颁糟。鍵和值都可以為任意對象類型。每個鍵僅出現一次喉悴,但相同值可出現多次棱貌。Dart對映射的支持由映射字面量和 Map 類型所提供。

以下是一些簡單的Dart映射箕肃,使用映射字面量創(chuàng)建:

var  gifts  =  {

  // Key:    Value

  'first':  'partridge',

  'second':  'turtledoves',

  'fifth':  'golden rings'

};

var  nobleGases  =  {

  2:  'helium',

  10:  'neon',

  18:  'argon',

};

Note: Dart推導 gifts 的類型為 Map<String, String> 键畴,而nobleGases 的類型為 Map<int, String>。如果你嘗試對任一映射添加錯誤類型的值突雪,分析器或運行時會拋出錯誤。更多相關信息涡贱,請參閱 類型推導咏删。

可以使用Map構造函數創(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';

Note: 你可能會希望看到 new Map() 而非僅僅是 Map()。從Dart 2中问词,關鍵字 new 為可選部分督函。更多詳情,參見使用構造函數激挪。

和JavaScript中一樣向已有映射添加鍵值對:

var  gifts  =  {'first':  'partridge'};

gifts['fourth']  =  'calling birds';  // 添加一個鍵值對

以JavaScript同樣的方式從映射中接收值:

var  gifts  =  {'first':  'partridge'};

assert(gifts['first']  ==  'partridge');

如果你在尋找一個不在映射中的鍵辰狡,會在返回中獲取到null:

var  gifts  =  {'first':  'partridge'};

assert(gifts['fifth']  ==  null);

使用 .length來獲取映射中鍵值對的數量:

var  gifts  =  {'first':  'partridge'};

gifts['fourth']  =  'calling birds';

assert(gifts.length  ==  2);

創(chuàng)建為編譯時常量的映射,在映射字面量之前添加const


final  constantMap  =  const  {

  2:  'helium',

  10:  'neon',

  18:  'argon',

};

// constantMap[2] = 'Helium'; // 取消本行注釋會導致報錯

在Dart 2.3中垄分,映射像列表一樣支持展開運算符 (......?) 及collection if 和 for宛篇。有關詳情及示例,參見 展開運算符提議控制流集合提議薄湿。

更多有關映射的信息叫倍,參見 泛型映射.

Runes

Dart中偷卧,runes是字符串的UTF-32代碼點。

Unicode為全球書寫系統(tǒng)中的每個字母吆倦、數字和符號定義了一個獨立的數值听诸。因為Dart字符串是一個UTF-16代碼單元的序列,在字符串中表達32位Unicode值要求有特殊的語法蚕泽。

通常表達一個Unicode代碼點的方式為 \uXXXX晌梨,其中XXXX是一個4位數的16進制值。例如须妻,心形字符串 (?) 為 \u2665仔蝌。要指定比4位16進制更多或更少的位數,需將值放在花括號中璧南。例如掌逛,笑臉emoji (??) 為 \u{1f600}

String 類有多個可用于提取rune信息的屬性司倚。 codeUnitAtcodeUnit屬性返回16-位代碼單元豆混。使用 runes 屬性來獲取字符串的rune。

以下示例描述runes动知、16-位代碼單元以及32-位代碼單元之間的關系皿伺。點擊 Run 來實時查看rune。

Screen Shot 2019-08-28 at 6.48.25 PM.png

Note: 在使用列表運算符操作runes時要小心盒粮。這種方法根據具體語言鸵鸥、字符集和操作可能會很容易崩潰。更多相關信息丹皱,參見Stack Overflow上的 如何倒排Dart中的字符串妒穴?

符號

符號(Symbol) 對象表示在Dart程序中聲明的一個運算符或標識符摊崭。你可能永遠都不會需要用到符號讼油,但它們對于通過名稱引用標識符的 API 有無限的價值,因為最小化會修改標識符的名稱但不修改標識符符號呢簸。

使用符號字面量獲取一個標識符的符號矮台,它只是#后接標識符。

#radix

#bar<code class="language-nocode">

符號字面量是編譯時常量根时。

函數

Dart是一個真面向對象語言瘦赫,因此即使是函數也是對象,并且擁有一個類型Function蛤迎。這表示函數可賦值給變量或作為參數傳遞給其它函數确虱。也可以調用將Dart類的實例看作函數來進行調用。更多詳情替裆,參見 可調用類蝉娜。

以下是實現一個函數的示例:

bool  isNoble(int  atomicNumber)  {

  return  _nobleGases[atomicNumber]  !=  null;

}

雖然高效Dart推薦 為公有 API 進行類型標注唱较,函數則省略類型時依然有效:


isNoble(atomicNumber)  {

  return  _nobleGases[atomicNumber]  !=  null;

}

對于僅包含一個表達式的函數,可以使用簡寫語法:

bool  isNoble(int  atomicNumber)  =>  _nobleGases[atomicNumber]  !=  null;

=> *expr* 語法是{ return *expr*; }的簡寫召川。 => 標記有時被稱為箭頭語法南缓。

Note: 僅有一個表達式 – 而不是一條語句 – 可以出現在箭頭(=>)和分號(;)之間。例如荧呐,你不能在這里放置一條 if語句汉形, 條件表達式

函數可以有兩種類型的參數:必選和可選倍阐。必選參數放在前面概疆,后接可選參數》逄拢可選參數可為命名參數或位置參數岔冀。

Note: 有些API – 尤其是Flutter widget構造函數 – 即使用對改造參數也僅使用命名參數。參見下面一節(jié)了解更多詳情概耻。

可選參數

可選參數可以為命名參數或位置參數使套,或者是兩者都有。

命名參數

在調用一個函數時鞠柄,你可以使用*paramName*: *value*指定命名參數侦高。例如:

enableFlags(bold:  true,  hidden:  false);

在定義函數時,使用 {*param1*, *param2*, …}來指定命名參數:


/// 設置bold 和 hidden標記 ...

void  enableFlags({bool  bold,  bool  hidden})  {...}

雖然命名參數是一種可選參數厌杜,通過可以@required 來標記它們以表示該參數是必須 – 即用戶必須為該參數提供一個值奉呛。例如:

const  Scrollbar({Key key,  @required Widget child})

如果有人嘗試不指定child參數就創(chuàng)建一個Scrollbar ,那么分析器會報出問題夯尽。

使用@required 標注瞧壮,需要依賴meta 包并導入 package:meta/meta.dart

位置參數

將一組函數參數封裝在 [] 中匙握,會將它們標記為可選位置參數:

String  say(String  from,  String  msg,  [String  device])  {

  var  result  =  '$from says $msg';

  if  (device  !=  null)  {

    result  =  '$result with a $device';

  }

  return  result;

}

以下是無添加可選參數調用該函數的示例:

assert(say('Bob',  'Howdy')  ==  'Bob says Howdy');

以下是使用了第3個參數調用該函數的示例:

assert(say('Bob',  'Howdy',  'smoke signal')  ==

    'Bob says Howdy with a smoke signal');

默認參數值

函數可以使用 = 來為命名參數和位置參數定義默認值咆槽。默認值必須為編譯時常量标沪。如未提供默認值寿桨,則默認值為 null筐咧。

以下是一個為命名參數設置默認值的示例:

/// 設置bold 和 hidden標記 ...

void  enableFlags({bool  bold  =  false,  bool  hidden  =  false})  {...}

// bold將為true; hidden將為false

enableFlags(bold:  true);

Deprecation note: 老代碼中可能會使用冒號 (:) 代替 = 來設置命名函數的默認值。原因是原來命名函數中僅支持 : 赠堵。該支持可能會被淘汰,所以我們推薦使 用= 來指定默認值法褥。

下面的示例展示如何為位置參數設置默認值:

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');

也可以傳遞列表或映射作為默認值茫叭。以下示例定義了一個函數doStuff(),它為 list參數指定了一個默認列表并為 gifts 參數指定了一個默認映射半等。

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()函數

每個應用必須有一個頂級的 main() 函數揍愁,它作為應用的入口呐萨。 main() 函數返回 void 并有一個可選參數l List<String>

以下是一個針對web應用的 main() 函數示例:

void  main()  {

  querySelector('#sample_text_id')

    ..text  =  'Click me!'

    ..onClick.listen(reverseText);

}

Note: 以下代碼中 .. 語法稱作一個 級聯莽囤。通過級聯谬擦,你可以對單個對象的成員執(zhí)行多個操作。

以下是一個針對接收參數的命令行應用的main() 函數示例:

// 像這樣運行它: dart args.dart 1 test

void  main(List<String>  arguments)  {

  print(arguments);

  assert(arguments.length  ==  2);

  assert(int.parse(arguments[0])  ==  1);

  assert(arguments[1]  ==  'test');

}

可以使用 args庫 來定義和解析命令行參數朽缎。

函數作為一等對象

你可以傳遞函數來作為另一個函數的參數惨远。例如:

void  printElement(int  element)  {

  print(element);

}

var  list  =  [1,  2,  3];

// 傳遞 printElement作為參數

list.forEach(printElement);

可將函數賦值給變量,如:

var  loudify  =  (msg)  =>  '!!! ${msg.toUpperCase()} !!!';

assert(loudify('hello')  ==  '!!! HELLO !!!');

該例使用了匿名函數话肖,更多相關內容請見下一節(jié)北秽。

匿名函數

大部分函數都是命名函數,如 main()printElement()最筒。你也可創(chuàng)建一個無名稱函數贺氓,稱為匿名函數,有時也稱為lambda 或閉包床蜘≌夼啵可以將匿名函數賦值給變量,那么例如就可以從集合中添加或刪除它悄泥。

匿名函數類似于命名函數 – 0或多個參數虏冻,在括號中由逗號和可選選類型標注分隔。

后面的代碼塊中包含函數體:

([[*Type*] *param1*[, …]]) { *codeBlock*; };

以下示例定義了一個帶有無類型參數 item 的匿名函數弹囚。對列表中的第一項所調用的函數厨相,打印包含在指定索引處的值的字符串。

var  list  =  ['apples',  'bananas',  'oranges'];

list.forEach((item)  {

  print('${list.indexOf(item)}: $item');

});

點擊 Run 執(zhí)行下面的代碼鸥鹉。

點擊查看

如果函數僅包含一條語句蛮穿,可將其簡化為使用箭頭標記。將如下行拷貝到DartPad中并點擊Run來驗證它的功能是相同的毁渗。

list.forEach(

    (item)  =>  print('${list.indexOf(item)}: $item'));

詞法作用域

Dart是一個詞法作用域語言践磅,表示變量的作用域僅由代碼的布局靜態(tài)決定。你可以“按照外部花括號” 來查看變量是否在作用域中灸异。

以下是一個變量在各自作用域中嵌套函數的示例:

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() 是如何使用每個級別的變量的府适,一路到頂級的變量。

詞法閉包

閉包是一個即使函數位置原作用域之外也可在詞法作用域中訪問變量的函數對象肺樟。

函數可封閉周圍作用域中所定義的變量檐春。在以下示例中, makeAdder() 捕獲變量 addBy么伯。不論返回的函數放在哪里疟暖,它都能記住 addBy

/// 返回一個將addBy添加到函數參數中的函數

Function  makeAdder(num addBy)  {

  return  (num  i)  =>  addBy  +  i;

}

void  main()  {

  // 創(chuàng)建一個加2的函數

  var  add2  =  makeAdder(2);

  // 創(chuàng)建一個加4的函數

  var  add4  =  makeAdder(4);

  assert(add2(3)  ==  5);

  assert(add4(3)  ==  7);

}

測試函數是否相等

下面是一個測試頂級函數、靜態(tài)方法和實例方法是否相等的示例:

void  foo()  {}  // 一個頂級函數

class  A  {

  static  void  bar()  {}  // 一個靜態(tài)方法

  void  baz()  {}  // 一個實例方法

}

void  main()  {

  var  x;

  // 對比頂級函數

  x  =  foo;

  assert(foo  ==  x);

  // 對比靜態(tài)方法

  x  =  A.bar;

  assert(A.bar  ==  x);

  // 對比實例方法

  var  v  =  A();  // A 的實例 #1

  var  w  =  A();  // A 的實例 #2

  var  y  =  w;

  x  =  w.baz;

  // 這些閉包引用相同的實例 (#2),

  // 因此它們相等俐巴。

  assert(y.baz  ==  x);

  // 這些閉包引用不同的實例骨望,

  // 因此它們不相等。

  assert(v.baz  !=  w.baz);

}

返回值

所有的函數都會返回值欣舵。如果未指定返回值擎鸠,語句 return null; 會隱式地附加到函數體中。

foo()  {}

assert(foo()  ==  null);

運算符

Dart定義了下表中顯示的運算符邻遏。你可以重載很多運算符糠亩,在重載運算符中進行了描述。

描述 運算符
一元后置 *expr*++ *expr*-- () [] . ?.
一元前置 -*expr* !*expr* ~*expr* ++*expr* --*expr*
乘除 * / % ~/
加減 + -
按位移 << >> >>>
按位與 &
按位異或 ^
按位或 ` `
關系和類型測試 >= > <= < as is is!
等于 == !=
邏輯與 &&
邏輯或 ` `
判空(null) ??
條件 *expr1* ? *expr2* : *expr3*
級聯 ..
賦值 = *= /= += -= &= ^= etc.

Warning: 運算符優(yōu)先級是對Dart解析器行為的估計准验。要獲取確定性的答案赎线,參見Dart語言規(guī)范中的語法。

在使用運算符時糊饱,可創(chuàng)建表達式垂寥。以下是一些運算符表達式的示例:

a++

a  +  b

a  =  b

a  ==  b

c  ?  a  :  b

a  is  T

運算符表格中, 每個運算符都比下面一行的運算符優(yōu)先級要高另锋。比如乘法運算符 % 的優(yōu)先級高于(因此先執(zhí)行)等號運算符 ==滞项,而它的優(yōu)先級又高于邏輯與運算符 &&。這個優(yōu)先級表示以下兩行代碼的執(zhí)行方式相同:

// 括號提升可讀性

if  ((n  %  i  ==  0)  &&  (d  %  i  ==  0))  ...

// 更驗閱讀夭坪,但是等價的

if  (n  %  i  ==  0  &&  d  %  i  ==  0)  ...

Warning: 對于使用兩個運算項的運算符文判,最左側的運算項決定使用哪個版本的運算符。例如室梅,如果有一個Vector對象和一個Point對象戏仓, aVector + aPoint 使用Vector版本的+。

算術運算符

Dart支持常見算術運算符亡鼠,如下表所示:

運算符 含義
+
-*expr* 一元減赏殃,也稱為否定(反轉表達式的符號)
*
/
~/ 整除,返回一個整數結果
% 獲取整數相除的余數(模)

示例:

assert(2  +  3  ==  5);

assert(2  -  3  ==  -1);

assert(2  *  3  ==  6);

assert(5  /  2  ==  2.5);  // 結果是雙精度類型

assert(5  ~/  2  ==  2);  // 結果是整型

assert(5  %  2  ==  1);  // 余數

assert('5/2 = ${5 ~/ 2} r ${5 % 2}'  ==  '5/2 = 2 r 1');

Dart也同時支持前置和后置遞增及遞減運算符间涵。

運算符 含義
++*var* *var* = *var* + 1 (表達式什為 *var* + 1)
*var*++ *var* = *var* + 1 (表達式值為 *var*)
--*var* *var* = *var* – 1 (表達式值為 *var* – 1)
*var*-- *var* = *var* – 1 (表達式值為 *var*)

示例:

var  a,  b;

a  =  0;

b  =  ++a;  // 在b獲取值之前對a遞增

assert(a  ==  b);  // 1 == 1

a  =  0;

b  =  a++;  // 在b獲取值之后對a遞增

assert(a  !=  b);  // 1 != 0

a  =  0;

b  =  --a;  // 在b獲取值之前對a遞減

assert(a  ==  b);  // -1 == -1

a  =  0;

b  =  a--;  // 在b獲取值之后對a遞減

assert(a  !=  b);  // -1 != 0

比較和關系運算符

下表中列出了比較和關系運算符的含義仁热。

運算符 含義
== 等于,參見下面的討論
!= 不等于
> 大于
< 小于
>= 大于等于
<= 小于等于

測試兩個對象x 和 y 是否表示相同的內容勾哩,使用 == 運算符抗蠢。(在極少的情況中,需要知道兩個對象是否是完全相同的對象思劳,轉而使用 identical()函數迅矛。) 以下展示 == 運算符如何運行:

  1. 如果xy 為null,如果兩者都為null則返回true敢艰,如果只一個為null則返回false诬乞。
  2. 返回*x*.==(*y*)方法運行的結果 册赛。(沒錯钠导,==這樣的運算符是對它們的第一項所調用的方法震嫉。你甚至可以重載很多運算符,包括 ==牡属, 可參見 重載運算符票堵。)

以下是使用每個比較和關系運算符的示例:

assert(2  ==  2);

assert(2  !=  3);

assert(3  >  2);

assert(2  <  3);

assert(3  >=  3);

assert(2  <=  3);

類型測試運算符

as, isis! 運算符對于在運行時檢查類型非常方便。

運算符 含義
as 對象類型轉換 (也用于指定 庫前綴)
is 如果對象有指定的類型時為true
is! 如果對象有指定的類型時為false

如果obj實現了T所指定的接口的話則 obj is T 的結果為 true逮栅。例如悴势,obj is Object 永遠為true。

使用 as 運算符將對象轉換為指定類型措伐。通常特纤,應使用它作為對象is測試的簡寫,后接使用該對象的表達式侥加。例如捧存,考慮使用如下代碼:


if  (emp is  Person)  {

  // 類型檢查

  emp.firstName  =  'Bob';

}

可以使用 as 運算符讓代碼更精簡:


(emp as  Person).firstName  =  'Bob';

Note: 兩種代碼并不等同。如果 emp 為null 或者不是Person担败,第1個例子(帶is)不會做任何事昔穴,第二個(帶as)拋出異常。

賦值運算符

如你所見提前,可以使用=運算符進行賦值吗货。僅為值為null的變量賦值時,使用 ??= 運算符狈网。

// 為a賦值

a  =  value;

// 若b為null時為 b 賦值宙搬,否則,b 保持不變

b  ??=  value;

復合賦值運算符如 += 將運算和賦值合并在一起孙援。

| = | –= | /= | %= | >>= | ^= |
| += | *= | ~/= | <<= | &= | |= |

以下是復合賦值運算符運行的方式:

復合賦值 比較表達式
對于運算符 op a *op*= b a = a *op* b
示例: a += b a = a + b

下例中使用賦值和復合賦值運算符:


var  a  =  2;  // 使用 =賦值

a *=  3;  // 賦值和乘法: a = a * 3

assert(a  ==  6);

邏輯運算符

可以使用邏輯運算符取反或合并布爾表達式害淤。

運算符 含義
!*expr* 對緊接著的表達式進行取反(修改false 為 true,反之亦然)
` ` 邏輯或
&& 邏輯與

以下是一個使用邏輯運算符的示例:

if  (!done  &&  (col  ==  0  ||  col  ==  3))  {

  // ...Do something...

}

按位及左移右移運算符

可以在Dart中操作數字的單個位拓售。通常窥摄,會對整型使用這些按位和移動運算符。

運算符 含義
&
` `
^ 異或
~*expr* 一元按位取反(0變成1础淤,1變成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);  // 右移

條件表達式

Dart有兩個運算符可以讓我們簡潔地運行可能會要求使用 if-else 語句的表達式:

*condition* ? *expr1* : *expr2*

若if條件為true, 運行 expr1 (并返回它的值)崭放,否則運行并返回 expr2的值。

*expr1* ?? *expr2*

expr1 為非空鸽凶,返回其值币砂,否則運行并返回 expr2的值。

在需要根據布爾表達式進行賦值時玻侥,考慮使用 ?:决摧。

var  visibility  =  isPublic  ?  'public'  :  'private';

如果要測試布爾表達式是否為null,考慮使用 ??

String  playerName(String  name)  =>  name  ??  'Guest';

前例至少可通過另外兩種方式進行編寫掌桩,但都沒有它簡潔:

// 使用?: 運算符的稍長版本

String  playerName(String  name)  =>  name  !=  null  ?  name  :  'Guest';

// 使用if-else語句的非常長的版本

String  playerName(String  name)  {

  if  (name  !=  null)  {

    return  name;

  }  else  {

    return  'Guest';

  }

}

級聯標記 (..)

級聯 (..) 允許我們對同一對象進行一系列操作边锁。除調用函數外,你還可以對相同的對象訪問字段波岛。這通趁┨常可節(jié)省創(chuàng)建臨時變量的步驟并讓我們能編寫列流暢的代碼。

思考如下代碼:

querySelector('#confirm')  // 獲取一個對象

  ..text  =  'Confirm'  // 使用它的成員

  ..classes.add('important')

  ..onClick.listen((e)  =>  window.alert('Confirmed!'));

第1個方法調用querySelector()则拷,返回一個選擇器對象贡蓖。緊接級聯標記的代碼對選擇器對象進行操作,它忽略所有后續(xù)可能返回的值煌茬。

前例等同于:T

var  button  =  querySelector('#confirm');

button.text  =  'Confirm';

button.classes.add('important');

button.onClick.listen((e)  =>  window.alert('Confirmed!'));

可以內嵌級聯斥铺。例如:

final  addressBook  =  (AddressBookBuilder()

      ..name  =  'jenny'

      ..email  =  'jenny@example.com'

      ..phone  =  (PhoneNumberBuilder()

            ..number  =  '415-555-0100'

            ..label  =  'home')

          .build())

    .build();

對于返回實際對象的函數構建級聯時要非常小心。例如坛善,如下代碼會失斀龈浮:


var  sb  =  StringBuffer();

sb.write('foo')

  ..write('bar');  // Error: method 'write' isn't defined for 'void'.

sb.write() 調用返回void,而無法對 void構建級聯浑吟。

Note: 嚴格的說笙纤,對級聯使用的“雙點號”標記并非運算符。它只是Dart語法的一部分组力。

其它運算符

我們已經在其它示例中看到過大部分剩余的運算符:

運算符 名稱 含義
() 函數應用 表示一個函數調用
[] 列表訪問 引用列表中所指定索引處的值
. 成員訪問 引用一個表達式的屬性省容;例如:foo.bar 從表達式foo中選擇屬性 bar
?. 條件成員訪問 類似 .燎字, 但最左側的運算項可以為null腥椒;例如: foo?.barfoo中選擇屬性 bar ,除非 foo 為 null (這時 foo?.bar 的值為 null)

更多有關., ?... 運算符的信息候衍,參見 笼蛛。

流程控制語句

可以使用以下方式來控制Dart 代碼中的流程

  • ifelse
  • for 循環(huán)
  • whiledowhile 循環(huán)
  • breakcontinue
  • switchcase
  • assert

也可以使用try-catchthrow 來影響控制流程,在 異常中有進行講解蛉鹿。

if和else

Dart 支持帶有可選的else語句的 if語句滨砍,如下例中所示。同時請參見 條件表達式妖异。

if  (isRaining())  {

  you.bringRainCoat();

}  else  if  (isSnowing())  {

  you.wearJacket();

}  else  {

  car.putTopDown();

}

不同于JavaScript惋戏,條件必須使用布爾值,其它的都不行他膳。參見 布爾型 獲取更多信息响逢。

for循環(huán)

你可以使用標準for循環(huán)進行迭代。例如:

var  message  =  StringBuffer('Dart is fun');

for  (var  i  =  0;  i  <  5;  i++)  {

  message.write('!');

}

Dart for 循環(huán)中的裝飾捕獲索引的值棕孙,避免JavaScript中所發(fā)現的常見問題舔亭。例如些膨,思考:

var  callbacks  =  [];

for  (var  i  =  0;  i  <  2;  i++)  {

  callbacks.add(()  =>  print(i));

}

callbacks.forEach((c)  =>  c());

會如所預期的先輸出 0 再輸出 1。但對比在JavaScript中則會先打印 2 再打印 2 钦铺。

如果所迭代的對象是一個 Iterable傀蓉,可以使用forEach() 方法。如果無需知道當前的迭代計數器的話使用 forEach() 是一個很好的選擇:

candidates.forEach((candidate)  =>  candidate.interview());

Iterable類如List 和 Set 還把持迭代for-in 形式:

var  collection  =  [0,  1,  2];

for  (var  x  in  collection)  {

  print(x);  // 0 1 2

}

while和do-while

while 循環(huán)在循環(huán)之前運行條件:

while  (!isDone())  {

  doSomething();

}

dowhile 在循環(huán)之后運行條件:

do  {

  printLine();

}  while  (!atEndOfPage());

break和continue

使用 break 來停止循環(huán):


while  (true)  {

  if  (shutDownRequested())  break;

  processIncomingRequests();

}

使用 continue 來跳至下一次迭代:

for  (int  i  =  0;  i  <  candidates.length;  i++)  {

  var  candidate  =  candidates[i];

  if  (candidate.yearsExperience  <  5)  {

    continue;

  }

  candidate.interview();

}

如果在使用列表或集這樣的Iterable時可以會以不同的方式編寫該示例:

candidates

    .where((c)  =>  c.yearsExperience  >=  5)

    .forEach((c)  =>  c.interview());

switch和case

Dart中的switch 語句使用==比較整型职抡、字符串或編譯時常量。 比較的對象必須都是相同類的實例(而非其子類型的)误甚,并且該類不能重載 ==.缚甩。枚舉類型switch 語句中可以良好運行。

Note: Dart中的switch語句針對受限的環(huán)境中窑邦,如解釋器或掃描器擅威。

每個非空 case 從句按照規(guī)則以break語句結束。其它結束非空 case 從名的有效方式有 continue, throwreturn 語句冈钦。

在沒有匹配的case從句時使用 default 從句來執(zhí)行代碼:


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 語句郊丛,因此產生了一個報錯:

var  command  =  'OPEN';

switch  (command)  {

  case  'OPEN':

    executeOpen();

    // ERROR: Missing break

  case  'CLOSED':

    executeClosed();

    break;

}

但是,Dart確實支持空的 case 從句允許越過的形式:

var  command  =  'CLOSED';

switch  (command)  {

  case  'CLOSED':  // 空的case直接越過

  case  'NOW_CLOSED':

    // 同時對CLOSED 和 NOW_CLOSED運行

    executeNowClosed();

    break;

}

如果你真的希望越過瞧筛,可以使用continue 語句及一個標簽:


var  command  =  'CLOSED';

switch  (command)  {

  case  'CLOSED':

    executeClosed();

    continue  nowClosed;

  // 繼續(xù)在nowClosed標簽處執(zhí)行

  nowClosed:

  case  'NOW_CLOSED':

    // 對CLOSED 和 NOW_CLOSED同時運行

    executeNowClosed();

    break;

}

case 從句可以有局部變量厉熟,僅在從句作用域內部可見。

斷言

在開發(fā)過程中较幌,可以使用斷言語句 assert(*condition*, *optionalMessage*); 來在布爾條件為false時打斷正常的執(zhí)行揍瑟。可以通過本導覽找到斷言語句的很多示例乍炉。以下是另外一些示例:


// 確保變量值為非null

assert(text  !=  null);

// 確保值小于100

assert(number  <  100);

// 確保這是一個https鏈接

assert(urlString.startsWith('https'));

要為斷言關聯消息绢片,對assert添加一個字符串作為第2個參數。

assert(urlString.startsWith('https'),

    'URL ($urlString) should start with "https".');

assert 的第1個參數可以是解析為布爾值的任意表達式岛琼。如果表達式的值為true底循,斷言成功且執(zhí)行繼續(xù)。如果它為false槐瑞,斷言失敗且會拋出異常(一個AssertionError)熙涤。

斷言到底做了什么呢?這取決于你所使用的工具和框架:

  • Flutter在調試模式中啟用斷言困檩。
  • 僅針對開發(fā)的工具如 dartdevc 通常默認啟用斷言灭袁。
  • 一些工具,如 dartdart2js窗看,支持通過命令行標記的斷言: --enable-asserts.

在生產模式下茸歧,會忽略斷言, assert 的參數不會被執(zhí)行显沈。

異常

Dart代碼可以拋出和捕獲異常软瞎。異常是表示預期外的事情發(fā)生時的報錯逢唤。如未捕獲到異常,拋出異常的 隔離(isolate)被掛起涤浇,并且通常隔離及其程序會被終止鳖藕。

不同睛Java,Dart的異常都是非檢查型異常只锭。方法未聲明它們所要拋出的異常著恩,那么也不要求你捕獲任何異常。

Dart提供 ExceptionError 類型蜻展,以及很多預定義的子類型喉誊。當然也可以定義自己的異常。但是Dart程序可拋出任意非空對象(不只是Exception和Error對象)來作為異常纵顾。

Throw

以下是一個拋出異常的示例:

throw  FormatException('Expected at least 1 section');

你也可以拋出自己的對象:


throw  'Out of llamas!';

Note: 生產質量的代碼通常拋出實現ErrorException的類型伍茄。

因為拋出異常是一個表達式,你可以在=>及其它允許使用表達式的任何地方拋出異常:

try  {

  breedMoreLlamas();

}  on  OutOfLlamasException  {

  buyMoreLlamas();

}

處理會拋出一個類型以上異常的代碼施逾,可以指定多個捕獲分分鐘敷矫。第一個匹配所拋出對象類型的catch從句會處理該異常。如果catch從句未指定類型汉额,該分分鐘可處理任意類型拋出的對象:

try  {

  breedMoreLlamas();

}  on  OutOfLlamasException  {

  // 一個具體異常

  buyMoreLlamas();

}  on Exception catch  (e)  {

  // 任何其它異常

  print('Unknown exception: $e');

}  catch  (e)  {

  // 無具體類型曹仗,處理所有類型

  print('Something really unknown: $e');

}

如以上代表所示,可以使用 oncatch 或者同時使用蠕搜。在需要指定異常類型時使用 on 整葡。在你的異常處理器需要異常對象時使用 catch

可以為catch()指定一個或兩個參數讥脐。第1個是拋出的異常遭居,第二是棧跟蹤 (一個 StackTrace對象).

try  {

  // ···

}  on Exception catch  (e)  {

  print('Exception details:\n $e');

}  catch  (e,  s)  {

  print('Exception details:\n $e');

  print('Stack trace:\n $s');

}

要部分處理異常,但允許其執(zhí)行旬渠,使用 rethrow 關鍵字俱萍。


void  misbehave()  {

  try  {

    dynamic foo  =  true;

    print(foo++);  // 運行時錯誤

  }  catch  (e)  {

    print('misbehave() partially handled ${e.runtimeType}.');

    rethrow;  // 允許調用者查看該異常

  }

}

void  main()  {

  try  {

    misbehave();

  }  catch  (e)  {

    print('main() finished handling ${e.runtimeType}.');

  }

}

Finally

要確保一些代碼不管是否拋出異常時都執(zhí)行,使用 finally 從句告丢。如果沒有 catch 從句匹配該異常枪蘑,在finally從句執(zhí)行后會推出異常。

try  {

  breedMoreLlamas();

}  finally  {

  // 即使在沒有拋出異常時也會清理

  cleanLlamaStalls();

}

finally 從任意匹配的catch 從句之后執(zhí)行:

try  {

  breedMoreLlamas();

}  catch  (e)  {

  print('Error: $e');  // 首先處理異常

}  finally  {

  cleanLlamaStalls();  // 然后進行清理

}

閱讀庫導覽的 異常 的一節(jié)了解更多信息岖免。

Dart是一個帶有類和基于mixin繼承的面向對象語言岳颇。每個對象都是類的實例,所有類都繼承自 Object.颅湘。* 基于mixin的繼承* 表示雖然每個類(除Object外)都只有一個超類话侧,一個類主體可在多個類級別中復用。

使用類成員

對象有由函數和數據(分別為方法和實例變量)組成的成員闯参。在調用方法時瞻鹏,對一個對象進行調用:該方法可訪問對象的函數和數據悲立。

使用點號 (.) 來引用于實例變量或方法:

var  p  =  Point(2,  2);

// 設置實例變量y的值

p.y  =  3;

// 獲取 y 的值

assert(p.y  ==  3);

// 對 p 調用 distanceTo()

num distance  =  p.distanceTo(Point(4,  4));

使用 ?. 代替 . 來避免最左側操作項為null時的異常:


// 如果p 不為null, 設置它的y 值為 4

p?.y  =  4;

使用構造函數

可以使用構造函數創(chuàng)建對象。構造函數名可為 *ClassName**ClassName*.*identifier*新博。例如薪夕,如下代碼使用Point()Point.fromJson() 構造函數創(chuàng)建 Point 對象:

var  p1  =  Point(2,  2);

var  p2  =  Point.fromJson({'x':  1,  'y':  2});

以下代碼有同樣的效果,但在構造函數名前使用可選的關鍵字 new

var  p1  =  new  Point(2,  2);

var  p2  =  new  Point.fromJson({'x':  1,  'y':  2});

Version note: 關鍵字 new Dart 2中成為可選項赫悄。

一些類提供 常量構造函數原献。要使用常量構造函數創(chuàng)建編譯時常量,在構造函數名前放置關鍵字 const

var  p  =  const  ImmutablePoint(2,  2);

構造兩個相同的編譯時常量會產生單個相同的實例:

var  a  =  const  ImmutablePoint(1,  1);

var  b  =  const  ImmutablePoint(1,  1);

assert(identical(a,  b));  // 它們是相同的實例埂淮!

在常量上下文中姑隅,可以在構造函數或字面量前省略 const 。例如同诫,查看如下創(chuàng)建一個const映射的代碼:

// 這里有很多const 關鍵字

const  pointAndLine  =  const  {

  'point':  const  [const  ImmutablePoint(0,  0)],

  'line':  const  [const  ImmutablePoint(1,  10),  const  ImmutablePoint(-2,  11)],

};

可以省略掉第一次使用之外的所有 const 關鍵字:


// 僅一個const, 它創(chuàng)建常量上下文

const  pointAndLine  =  {

  'point':  [ImmutablePoint(0,  0)],

  'line':  [ImmutablePoint(1,  10),  ImmutablePoint(-2,  11)],

};

如果常量構造函數在常量上下文之外且未使用 const調用,它創(chuàng)建一個非常量對象樟澜。

var  a  =  const  ImmutablePoint(1,  1);  // 創(chuàng)建一個常量

var  b  =  ImmutablePoint(1,  1);  // 不創(chuàng)建常量

assert(!identical(a,  b));  // 不是相同的實例误窖!

Version note: 關鍵字 const 在Dart 2的常量上下文成為可選。

獲取一個對象的類型

要在運行時獲取對象的類型秩贰,可以使用Object的 runtimeType 屬性霹俺,它返回一個 Type 對象。


print('The type of a is ${a.runtimeType}');

到這里毒费,你已學習了如何使用類丙唧。本節(jié)后面的部分展示如何實現類。

實例變量

以下是如何聲明實例變量:


class  Point  {

  num  x;  // 聲明實例變量 x, 初始值為 null

  num  y;  // 聲明 y, 初始值為 null

  num  z  =  0;  // 聲明 z, 初始值為 0

}

所有未初始化的實例變量的值為 null觅玻。

所有的實例變量生成一個getter 方法想际。非final實例變量也生成一個隱式setter 方法。更多詳情溪厘,參見getters和setters胡本。

class  Point  {

  num  x;

  num  y;

}

void  main()  {

  var  point  =  Point();

  point.x  =  4;  // 使用針對x 的setter方法

  assert(point.x  ==  4);  // 使用針對x 的getter方法

  assert(point.y  ==  null);  // 默認值為null

}

如果在其聲明處實例化實例變量(而非在構造函數或方法中進行),在實例創(chuàng)建時設置值畸悬,即在構造函數及期初始化程序列表執(zhí)行前侧甫。

本文首發(fā)地址:Alan Hou的個人博客

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蹋宦,隨后出現的幾起案子披粟,更是在濱河造成了極大的恐慌,老刑警劉巖冷冗,帶你破解...
    沈念sama閱讀 222,183評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件守屉,死亡現場離奇詭異,居然都是意外死亡蒿辙,警方通過查閱死者的電腦和手機溉旋,發(fā)現死者居然都...
    沈念sama閱讀 94,850評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來告材,“玉大人邑遏,你說我怎么就攤上這事〕赘簦” “怎么了?”我有些...
    開封第一講書人閱讀 168,766評論 0 361
  • 文/不壞的土叔 我叫張陵,是天一觀的道長秽荤。 經常有香客問我,道長柠横,這世上最難降的妖魔是什么窃款? 我笑而不...
    開封第一講書人閱讀 59,854評論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮牍氛,結果婚禮上晨继,老公的妹妹穿的比我還像新娘。我一直安慰自己搬俊,他們只是感情好紊扬,可當我...
    茶點故事閱讀 68,871評論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著唉擂,像睡著了一般餐屎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上玩祟,一...
    開封第一講書人閱讀 52,457評論 1 311
  • 那天腹缩,我揣著相機與錄音,去河邊找鬼空扎。 笑死藏鹊,一個胖子當著我的面吹牛,可吹牛的內容都是我干的转锈。 我是一名探鬼主播伙判,決...
    沈念sama閱讀 40,999評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼黑忱!你這毒婦竟也來了宴抚?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,914評論 0 277
  • 序言:老撾萬榮一對情侶失蹤甫煞,失蹤者是張志新(化名)和其女友劉穎菇曲,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體抚吠,經...
    沈念sama閱讀 46,465評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡常潮,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,543評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了楷力。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喊式。...
    茶點故事閱讀 40,675評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡孵户,死狀恐怖,靈堂內的尸體忽然破棺而出岔留,到底是詐尸還是另有隱情夏哭,我是刑警寧澤,帶...
    沈念sama閱讀 36,354評論 5 351
  • 正文 年R本政府宣布献联,位于F島的核電站竖配,受9級特大地震影響,放射性物質發(fā)生泄漏里逆。R本人自食惡果不足惜进胯,卻給世界環(huán)境...
    茶點故事閱讀 42,029評論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望原押。 院中可真熱鬧胁镐,春花似錦、人聲如沸诸衔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,514評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽署隘。三九已至宠能,卻和暖如春亚隙,著一層夾襖步出監(jiān)牢的瞬間磁餐,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,616評論 1 274
  • 我被黑心中介騙來泰國打工阿弃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留诊霹,地道東北人。 一個月前我還...
    沈念sama閱讀 49,091評論 3 378
  • 正文 我出身青樓渣淳,卻偏偏與公主長得像脾还,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子入愧,可洞房花燭夜當晚...
    茶點故事閱讀 45,685評論 2 360

推薦閱讀更多精彩內容