Dart官方文檔翻譯(一)(Dart之旅)

這篇文章將會(huì)向你展示如何使用Dart的每一個(gè)知識點(diǎn),包括變量,操作符,類,類庫,但這是在你已經(jīng)有一個(gè)其他語言的編碼經(jīng)驗(yàn)的前提下。
為了學(xué)習(xí)Dart更多關(guān)于Dart的核心類庫,請查看A Tour of the Dart Libraries,當(dāng)你想知道更多語言特征,挺查閱Dart language specification

你可以通過DartPad 來嘗試運(yùn)行Dart代碼:Open DartPad

一個(gè)基本的Dart程序

// Define a function.
printInteger(int aNumber) {
  print('The number is $aNumber.'); // Print to console.
}

// This is where the app starts executing.
main() {
  var number = 42; // Declare and initialize a variable.
  printInteger(number); // Call a function.
}

以下是此程序使用的適用于所有(或幾乎所有)Dart應(yīng)用程序的內(nèi)容:

// This is a comment.

單行注釋。Dart還支持多行和文檔注釋。有關(guān)詳情,請參閱注釋

int

整數(shù)類型。一些其他的內(nèi)置類型StringListbool

42

一個(gè)整數(shù)字面值,這是一個(gè)編譯時(shí)常量。

print()

一個(gè)方便的輸出函數(shù)。

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

字符串字面值。

$variableName(或)${expression}

字符串插值:包括字符串字面值內(nèi)部的變量或表達(dá)式的字符串。有關(guān)更多信息,請參閱 字符串

main()

一個(gè)特殊的頂級(top)的必須的(requared)app應(yīng)用的入口函數(shù),有關(guān)更多信息,請參閱 main()函數(shù)

var

一種聲明變量而不指定其類型的方法。

重要的概念

當(dāng)您了解Dart語言時(shí),請記住以下事實(shí)和概念:

  • 變量所指向的所有值都是對象,每個(gè)對象都是一個(gè)的實(shí)例。數(shù)字,函數(shù)(函數(shù)也是一個(gè)變量)和 null對象等。所有對象都繼承自Object類。
  • 盡管Dart是強(qiáng)類型的,但類型聲明是可選的,因?yàn)镈art可以推斷類型。在上面的代碼中,number 推斷為類型int。如果要明確說明不需要任何類型,請 使用特殊類型dynamic
  • Dart支持泛型類型,如List<int>(整數(shù)List)或List<dynamic>(任何類型的對象List)。
  • Dart支持頂級函數(shù)(例如main()),以及綁定到類或?qū)ο蟮暮瘮?shù)(分別是靜態(tài)和實(shí)例方法)。您還可以在函數(shù)內(nèi)創(chuàng)建函數(shù)(嵌套函數(shù)或本地函數(shù))。
  • 類似地,Dart支持頂級變量,以及綁定到類或?qū)ο蟮淖兞浚o態(tài)和實(shí)例變量)。實(shí)例變量有時(shí)稱為字段或?qū)傩浴?/li>
  • 與Java,Dart不具備關(guān)鍵字publicprotectedprivate。如果標(biāo)識符以下劃線(_)開頭,則它對其庫是私有的。有關(guān)詳細(xì)信息,請參閱 庫和可見性
  • 標(biāo)識符可以以字母或下劃線(_)開頭,后跟這些字符加數(shù)字的任意組合。
  • Dart可以使用表達(dá)式(具有運(yùn)行時(shí)值)和 語句(不具有)。例如,條件表達(dá)式 condition ? expr1 : expr2的值為expr1expr2。將其與if-else語句進(jìn)行比較,語句沒有任何值。語句通常包含一個(gè)或多個(gè)表達(dá)式,但表達(dá)式不能直接包含語句。
  • Dart工具可以報(bào)告兩種問題:警告錯(cuò)誤。警告只是表明您的代碼可能無法正常工作,但它們不會(huì)阻止您的程序執(zhí)行。錯(cuò)誤可以是編譯時(shí)或運(yùn)行時(shí)。編譯時(shí)錯(cuò)誤會(huì)阻止代碼執(zhí)行; 運(yùn)行時(shí)錯(cuò)誤導(dǎo)致 代碼執(zhí)行時(shí)引發(fā)異常

關(guān)鍵字

下表列出了Dart語言的關(guān)鍵字:

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

避免使用這些單詞作為標(biāo)識符。但是,如有必要,標(biāo)有上標(biāo)的關(guān)鍵字可以是標(biāo)識符:

  • 帶有上標(biāo)1的單詞是上下文關(guān)鍵字,僅在特定位置具有含義。
  • 帶有上標(biāo)2的單詞是內(nèi)置標(biāo)識符。為了簡化將JavaScript代碼移植到Dart的任務(wù),這些關(guān)鍵字在大多數(shù)地方都是有效的標(biāo)識符,但它們不能用作類或類型名稱,也不能用作導(dǎo)入前綴。
  • 帶有上標(biāo)3的單詞是與Dart 1.0發(fā)布后添加的異步支持相關(guān)的更新,有限的保留字。不能使用awaityield作為任何函數(shù)體中的標(biāo)識符標(biāo)記asyncasync*sync*
    表中的所有其他單詞都是保留字,不能是標(biāo)識符。

變量

這是創(chuàng)建變量并初始化它的示例:

var name = 'Bob' ; 

變量存儲(chǔ)引用。名為name的變量指向String值為“Bob” 的對象。
name推斷變量的類型String,但您可以通過指定它來更改該類型。如果對象不限于單一類型,請按照設(shè)計(jì)準(zhǔn)則指定Objectdynamic類型 。

dynamic name = 'Bob' ; 

另一種選擇是顯式聲明類型:

String name = 'Bob' ; 

注意: 此頁面遵循 風(fēng)格指南建議 使用var,而不是指定類型,用于局部變量。

默認(rèn)值

未初始化的變量的初始值為null。即使是具有數(shù)字類型的變量最初也是null,因?yàn)閿?shù)字 - 就像Dart中的其他所有都是對象。

int lineCount ; 
assert (lineCount == null );

注意:生產(chǎn)環(huán)境代碼中將忽略assert() 調(diào)用。在開發(fā)期間, 除非條件為真,否則拋出異常。有關(guān)詳細(xì)信息,請參閱斷言

Final and const

如果您從未打算更改變量,請使用final或const代替var或替代類型。最終變量只能設(shè)置一次; const變量是編譯時(shí)常量。(Const變量是隱式final的。)final的頂級或類變量在第一次使用時(shí)被初始化。
以下是創(chuàng)建和設(shè)置最終變量的示例:

final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';

您無法更改最終變量的值:

name = 'Alice' ; //錯(cuò)誤:最終變量只能設(shè)置一次。  

使用const為您要為變量的編譯時(shí)間常數(shù)。如果const變量在類級別,請聲明為static const。在聲明變量的地方,將值設(shè)置為編譯時(shí)常量,例如數(shù)字或字符串字面值,const變量或?qū)Τ?shù)進(jìn)行算術(shù)運(yùn)算的結(jié)果:

const bar = 1000000; // 壓力單位 (dynes/cm2)
const double atm = 1.01325 * bar; // 標(biāo)準(zhǔn)大氣壓

該const關(guān)鍵字不只是聲明常數(shù)變量。您還可以使用它來創(chuàng)建常量值,以及聲明創(chuàng)建常量值的構(gòu)造函數(shù)。任何變量都可以具有常量值。

var foo = const [];
final bar = const [];
const baz = []; //相當(dāng)于`const []`  

您可以省略聲明const的初始化表達(dá)式,如上所述。有關(guān)詳細(xì)信息,請參閱不要冗余地使用constconst``baz
您可以更改非final,非const變量的值,即使它曾經(jīng)有一個(gè)const值:

foo = [1, 2, 3]; // Was const []

您無法更改const變量的值:

baz = [ 42 ]; //錯(cuò)誤:無法為常量變量賦值。  

有關(guān)使用const創(chuàng)建常量值的更多信息,請參閱 ListsMapsClasses

內(nèi)置類型

Dart語言特別支持以下類型:

  • numbers
  • strings
  • booleans
  • lists (also known as arrays)
  • sets
  • maps
  • runes (for expressing Unicode characters in a string)
  • symbols
    您可以使用字面值初始化任何這些特殊類型的對象。例如,'this is a string'是一個(gè)字符串字面值,true是一個(gè)布爾字面值。
    因?yàn)镈art中的每個(gè)變量都引用一個(gè)對象 - 一個(gè)類的實(shí)例 - 您通常可以使用構(gòu)造函數(shù)來初始化變量。一些內(nèi)置類型有自己的構(gòu)造函數(shù)。例如,您可以使用Map()構(gòu)造函數(shù)來創(chuàng)建Map。

Numbers

Dart 數(shù)字有兩種形式:
int
整數(shù)值不大于64位,具體取決于平臺。在Dart VM上,值可以是-2 63到2 63 - 1.編譯為JavaScript的Dart使用 JavaScript編號, 允許從-2 53到2 53 - 1的值。

double
64位(雙精度)浮點(diǎn)數(shù),由IEEE 754標(biāo)準(zhǔn)規(guī)定。
這兩個(gè)intdouble的亞型num num類型支持基本的運(yùn)算符,如+, - ,/和*,以及abs()ceil()floor()其他方法已在其中定義。(按位運(yùn)算符,例如>>,在int類中定義。)如果num及其子類型沒有您要查找的內(nèi)容,則 dart:math庫可能會(huì)定義。
整數(shù)是沒有小數(shù)點(diǎn)的數(shù)字。以下是定義整型字面值的一些示例:

var x = 1;
var hex = 0xDEADBEEF;

如果數(shù)字包含小數(shù),則為雙精度數(shù)。以下是定義雙精度字面值的一些示例:

var y = 1.1;
var exponents = 1.42e5;

從Dart 2.1開始,必要時(shí)整型字面值會(huì)自動(dòng)轉(zhuǎn)換為雙精度數(shù):

double z = 1; // Equivalent to double z = 1.0.

版本說明: 在Dart 2.1之前,在雙精度數(shù)變量賦值為整型字面值是錯(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)的按位移位(<<,>>),AND(&)和OR(|)運(yùn)算符。例如:

assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111

字面值數(shù)字是編譯時(shí)常量。許多算術(shù)表達(dá)式也是編譯時(shí)常量,因?yàn)樗鼈兊牟僮鲾?shù)是編譯為數(shù)字的編譯時(shí)常量。

const msPerSecond = 1000;
const secondsUntilRetry = 5;
const msUntilRetry = secondsUntilRetry * msPerSecond;

Strings

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.";

您可以使用表達(dá)式將表達(dá)式的值放在字符串中 。如果表達(dá)式是標(biāo)識符,則可以跳過{}。要獲取與對象相對應(yīng)的字符串,Dart會(huì)調(diào)用該對象的方法。${expression}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!');

注: 在==兩個(gè)物體操作測試是否是等價(jià)的。如果兩個(gè)字符串包含相同的代碼單元序列,則它們是等效的。(這一點(diǎn)和java是不同的,java,String的==運(yùn)算符,只有當(dāng)?shù)刂芬粯樱置嬷狄粯樱拍苁瓜嗟鹊模琩art String 的== 相當(dāng)于java String的equal)

您可以使用相鄰的字符串字面值或+ 運(yù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.');

創(chuàng)建多行字符串的另一種方法:使用帶有單引號或雙引號的三引號:

var s1 = '''
You can create
multi-line strings like this one.
''';

var s2 = """This is also a
multi-line string.""";

您可以通過為其添加前綴來創(chuàng)建“raw”字符串r:

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

有關(guān)如何在字符串中表示Unicode字符的詳細(xì)信息,請參閱Runes

字符串字面值是編譯時(shí)常量,因?yàn)槿魏尾逯当磉_(dá)式是一個(gè)編譯時(shí)常量,其值為null或數(shù)值,字符串或布爾值。

// These work in a const string.
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// These do NOT work in a const string.
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';

有關(guān)使用字符串的更多信息,請參閱 字符串和正則表達(dá)式

Booleans

為了表示布爾值,Dart具有一個(gè)名為的類型bool。只有兩個(gè)對象具有bool類型:boolean 字面值 true和false,它們都是編譯時(shí)常量。

Dart的類型安全意味著你不能使用像或 那樣的代碼,如下:

if (nonbooleanValue)
  assert (nonbooleanValue)

應(yīng)該明確能計(jì)算出值:

// Check for an empty string.
var fullName = '';
assert(fullName.isEmpty);

// Check for zero.
var hitPoints = 0;
assert(hitPoints <= 0);

// Check for null.
var unicorn;
assert(unicorn == null);

// Check for NaN.
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

Lists

也許幾乎每種編程語言中最常見的集合是數(shù)組或有序的對象組。在Dart中,數(shù)組是 List對象,因此大多數(shù)人只是將它們稱為列表

Dart List文字看起來像JavaScript數(shù)組字面值。這是一個(gè)簡單的Dart List:

var list = [1, 2, 3];

注意: Dart推斷出list有類型List<int>。如果嘗試將非整數(shù)對象添加到此List,則分析器或運(yùn)行時(shí)會(huì)引發(fā)錯(cuò)誤。有關(guān)更多信息,請閱讀 類型推斷。

List使用從零開始的索引,list.length - 1是最后一個(gè)元素的索引。您可以獲得List的長度并像在JavaScript中一樣引用List元素:

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

要?jiǎng)?chuàng)建一個(gè)編譯時(shí)常量const的List,請?jiān)贚ist文字前添加const

var constantList = const [1, 2, 3];
// constantList[1] = 1; // Uncommenting this causes an error. 

List類型有許多方便的方法來操作List。有關(guān)List的更多信息,請參閱泛型集合

Sets

Dart中的set是一組無序的獨(dú)特item集合。對集合的Dart支持由set 字面值和Set類型提供。
這是一個(gè)簡單的Dart集,使用set 字面值創(chuàng)建:

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

Dart推斷出halogens具有該類型 Set<String>。如果您嘗試向集合中添加錯(cuò)誤類型的值,則分析器或運(yùn)行時(shí)會(huì)引發(fā)錯(cuò)誤。有關(guān)更多信息,請閱讀 類型推斷。

要?jiǎng)?chuàng)建一個(gè)空集,請使用{}前面帶有類型參數(shù),或者指定{}給類型的變量Set:

var names = <String>{};
// Set<String> names = {}; // This works, too.
// var names = {}; // Creates a map, not a set.

Set還是Map? Map字面值的語法類似于Set字面值的語法。由于Map的優(yōu)先級靠前,因此{(lán)}默認(rèn)為Map類型。如果您忘記了類型注釋{}或它所分配的變量,則Dart會(huì)創(chuàng)建一個(gè)類型的對象Map<dynamic, dynamic>。

使用add()或addAll()方法將項(xiàng)添加到現(xiàn)有集:

var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);

使用.length得到的一組Set的數(shù)量:

var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);

要?jiǎng)?chuàng)建一個(gè)編譯時(shí)常量const的集合,請?jiān)趕et literal之前添加const

final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
// constantSet.add('helium'); // Uncommenting this causes an error.

有關(guān)集的更多信息,請參閱 泛型Set

Maps

通常,映射是關(guān)聯(lián)鍵和值的對象。鍵和值都可以是任何類型的對象。每個(gè)只出現(xiàn)一次,但您可以多次使用相同的。Map的Dart支持由Map字面值和Map類型提供。

這里有幾個(gè)簡單的Dart Map例子,使用Map字面值創(chuàng)建:

var gifts = {
  // Key:    Value
  'first': 'partridge',
  'second': 'turtledoves',
  'fifth': 'golden rings'
};

var nobleGases = {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

Dart推斷出gifts的類型 Map<String, String>以及nobleGases類型的 Dart Map<int, String>。如果您嘗試將錯(cuò)誤類型的值添加到任一映射,則分析器或運(yùn)行時(shí)會(huì)引發(fā)錯(cuò)誤。有關(guān)更多信息,請閱讀 類型推斷。

您可以使用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';

注意: 您可能想添加new而不僅僅是Map()。從Dart 2開始,new關(guān)鍵字是可選的。有關(guān)詳細(xì)信息,請參閱使用構(gòu)造函數(shù)

像在JavaScript中一樣,將新的鍵值對添加到現(xiàn)有Map中:

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair

以與在JavaScript中相同的方式從Map中檢索值:

var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');

如果您查找不在Map中的鍵,則會(huì)得到null作為回報(bào):

var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);

使用.length得到的映射中的鍵值對的數(shù)量:

var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);

要?jiǎng)?chuàng)建一個(gè)編譯時(shí)常量const的Map,請?jiān)贛ap字面值之前添加const
有關(guān)Map的更多信息,請參閱 泛型Map

Runes

在Dart中,Runes是字符串的UTF-32表達(dá)。
Unicode為世界上所有書寫系統(tǒng)中使用的每個(gè)字母,數(shù)字和符號定義唯一的數(shù)值。由于Dart字符串是UTF-16代碼單元的序列,因此在字符串中表示32位Unicode值需要特殊語法。
表達(dá)Unicode代碼點(diǎn)的常用方法是 \uXXXX,XXXX是4位十六進(jìn)制值。例如,心臟角色(?)是\u2665。要指定多于或少于4個(gè)十六進(jìn)制數(shù)字,請將值放在大括號中。例如,笑的表情符號(??)是\u{1f600}。
字符串 類有幾個(gè)屬性,你可以用它來提取Runes信息。在codeUnitAtcodeUnit屬性返回16位編碼單元。使用該runes屬性獲取字符串的Runes。

以下示例說明了符文,16位代碼單元和32位代碼點(diǎn)之間的關(guān)系。

main() {
  var clapping = '\u{1f44f}';
  print(clapping);
  print(clapping.codeUnits);
  print(clapping.runes.toList());

  Runes input = new Runes(
      '\u2665  \u{1f605}  \u{1f60e}  \u{1f47b}  \u{1f596}  \u{1f44d}');
  print(new String.fromCharCodes(input));
}

注意: 使用列表操作操作符文時(shí)要小心。這種方法很容易使字符串解體,具體取決于特定的語言,字符集和操作。有關(guān)更多信息,請參閱 如何在Dart中反轉(zhuǎn)字符串?在Stack Overflow上。

Symbols

Symbol對象表示在Dart程序中聲明的運(yùn)算符或標(biāo)識符。您可能永遠(yuǎn)不需要使用符號,但它們對于按名稱引用標(biāo)識符的API非常有用,因?yàn)榭s小會(huì)更改標(biāo)識符名稱而不會(huì)更改標(biāo)識符符號。要獲取標(biāo)識符的符號,請使用符號文字,它只是#后跟標(biāo)識符:(這一段實(shí)在不會(huì)翻譯了- -)
要獲取標(biāo)識符的符號,請使用符號文字, #后面跟著標(biāo)識符:

 #radix
 #bar

Symbols文字是編譯時(shí)常量。

Functions

Dart是一種真正的面向?qū)ο笳Z言,因此即使是函數(shù)也是對象并且具有類型Function。 這意味著函數(shù)可以分配給變量或作為參數(shù)傳遞給其他函數(shù)。您也可以調(diào)用Dart類的實(shí)例,就好像它是一個(gè)函數(shù)一樣。有關(guān)詳細(xì)信息,請參閱Callable classes

以下是實(shí)現(xiàn)函數(shù)的示例:

bool isNoble(int atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

雖然Effective Dart建議 為公共API聲明返回值類型,但如果省略類型,該函數(shù)仍然有效:

isNoble(atomicNumber) {
  return _nobleGases[atomicNumber] != null;
}

對于只包含一個(gè)表達(dá)式的函數(shù),可以使用簡寫語法:

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

這個(gè) => 是{ return expr; }的速記 . 。有時(shí)將=> 表示法稱為箭頭語法。
只有表達(dá)式(而不是語句)能夠出現(xiàn)在箭頭(=>)和分號(;)之間。例如,您不能在其中放置if語句,但可以使用條件表達(dá)式
函數(shù)可以有兩種類型的參數(shù):必需和可選。首先列出所需參數(shù),然后列出任何可選參數(shù)。命名的可選參數(shù)也可以標(biāo)記為@required。有關(guān)詳細(xì)信息,請參閱下一節(jié)。

可選參數(shù)

可選參數(shù)可以是位置參數(shù),也可以是名稱參數(shù),但不能同時(shí)包含

可選的名稱參數(shù)

調(diào)用函數(shù)時(shí),可以使用指定名稱參數(shù) 。例如:paramName: value

enableFlags (bold :true ,hidden :false );  

定義函數(shù)時(shí),用于 指定名稱參數(shù):{param1, param2, …}

/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}

Flutter實(shí)例創(chuàng)建表達(dá)式可能變得復(fù)雜,因此窗口小部件構(gòu)造函數(shù)僅使用命名參數(shù)。這使得實(shí)例創(chuàng)建表達(dá)式更易于閱讀。
您可以使用@required在任何Dart代碼(不僅僅是Flutter)中注釋命名參數(shù), 以指示它是必需參數(shù)。例如:

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

當(dāng)一個(gè)Scrollbar構(gòu)造,當(dāng)必要參數(shù)缺少時(shí),編譯器會(huì)報(bào)錯(cuò)。
requaredmate包中定義。可以package:meta/meta.dart直接導(dǎo)入 ,也可以導(dǎo)入另一個(gè)導(dǎo)出的包 meta,例如Flutter package:flutter/material.dart

可選的位置參數(shù)

包裝一組函數(shù)參數(shù)將[]它們標(biāo)記為可選的位置參數(shù):

String say(String from, String msg, [String device]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  return result;
}

這是一個(gè)在沒有可選參數(shù)的情況下調(diào)用此函數(shù)的示例:

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

以下是使用第三個(gè)參數(shù)調(diào)用此函數(shù)的示例:

assert(say('Bob', 'Howdy', 'smoke signal') ==
    'Bob says Howdy with a smoke signal');

默認(rèn)參數(shù)值
您的函數(shù)可用于=定義命名和位置參數(shù)的默認(rèn)值。默認(rèn)值必須是編譯時(shí)常量。如果未提供默認(rèn)值,則默認(rèn)值為null。
以下是為命名參數(shù)設(shè)置默認(rèn)值的示例:

/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold = false, bool hidden = false}) {...}

// bold will be true; hidden will be false.
enableFlags(bold: true);

棄用注釋: 舊代碼可能使用冒號(:)而不是= 設(shè)置命名參數(shù)的默認(rèn)值。原因是最初只:支持命名參數(shù)。該支持可能已被棄用,因此我們建議您 使用=指定默認(rèn)值。

下一個(gè)示例顯示如何設(shè)置位置參數(shù)的默認(rèn)值:

String say(String from, String msg,
    [String device = 'carrier pigeon', String mood]) {
  var result = '$from says $msg';
  if (device != null) {
    result = '$result with a $device';
  }
  if (mood != null) {
    result = '$result (in a $mood mood)';
  }
  return result;
}

assert(say('Bob', 'Howdy') ==
    'Bob says Howdy with a carrier pigeon');

您還可以將List或Map作為默認(rèn)值傳遞。以下示例定義了一個(gè)函數(shù),該函數(shù)doStuff()指定參數(shù)的默認(rèn)List和list 參數(shù)的默認(rèn)Map 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()函數(shù)

每個(gè)應(yīng)用程序都必須具有頂級main()功能,該功能用作應(yīng)用程序的入口點(diǎn)。該main()函數(shù)返回void并具有List<String>參數(shù)的可選參數(shù)。
以下main()是Web應(yīng)用程序功能的示例:

void main() {
  querySelector('#sample_text_id')
    ..text = 'Click me!'
    ..onClick.listen(reverseText);
}

注意:..前面代碼中 的語法稱為級聯(lián)。使用級聯(lián),您可以對單個(gè)對象的成員執(zhí)行多個(gè)操作。

以下main()是帶參數(shù)的命令行應(yīng)用程序的函數(shù)示例:

// Run the app like this: 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庫來定義和解析命令行參數(shù)。

Function 作為第一類對象的功能

您可以將函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)。例如:

void printElement(int element) {
  print(element);
}

var list = [1, 2, 3];

// Pass printElement as a parameter.
list.forEach(printElement);

您還可以為變量分配函數(shù),例如:

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

此示例使用了匿名函數(shù)。更多關(guān)于下一節(jié)的內(nèi)容。

匿名函數(shù)

大多數(shù)函數(shù)都被命名,例如main()或printElement()。您還可以創(chuàng)建一個(gè)名為匿名函數(shù)的無名函數(shù),有時(shí)也可以創(chuàng)建一個(gè)lambda或閉包。您可以為變量分配匿名函數(shù),以便例如可以在集合中添加或刪除它。

匿名函數(shù)看起來類似于命名函數(shù) - 零個(gè)或多個(gè)參數(shù),在逗號和括號之間用逗號和可選類型注釋分隔。

后面的代碼塊包含函數(shù)的主體:

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

以下示例使用無類型參數(shù)item定義匿名函數(shù),為List中的每個(gè)項(xiàng)調(diào)用的函數(shù)將打印一個(gè)包含指定索引處的值的字符串。

var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
  print('${list.indexOf(item)}: $item');
});

如果函數(shù)只包含一個(gè)語句,則可以使用箭頭表示法縮短它。

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

作用域

Dart是有作用域的語言,這意味著變量的范圍是靜態(tài)確定的,只需通過代碼的布局。您可以“向外跟隨花括號”以查看變量是否在范圍內(nèi)。
以下是每個(gè)范圍級別包含變量的嵌套函數(shù)示例:

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()每個(gè)級別的變量,一直到頂級。

閉包

一個(gè)閉包是能夠訪問在其作用域的變量的函數(shù)的對象,即使當(dāng)函數(shù)用于其原來的范圍之外。
函數(shù)可以關(guān)閉周圍范圍中定義的變量。在以下示例中,makeAdder()捕獲變量addBy。無論返回的函數(shù)在哪里,它都記錄addBy。

/// Returns a function that adds [addBy] to the
/// function's argument.
Function makeAdder(num addBy) {
  return (num i) => addBy + i;
}

void main() {
  // Create a function that adds 2.
  var add2 = makeAdder(2);

  // Create a function that adds 4.
  var add4 = makeAdder(4);

  assert(add2(3) == 5);
  assert(add4(3) == 7);
}

測試函數(shù)是否相等

以下是測試頂級函數(shù),靜態(tài)方法和實(shí)例方法的相等性的示例:

void foo() {} // A top-level function

class A {
  static void bar() {} // A static method
  void baz() {} // An instance method
}

void main() {
  var x;

  // Comparing top-level functions.
  x = foo;
  assert(foo == x);

  // Comparing static methods.
  x = A.bar;
  assert(A.bar == x);

  // Comparing instance methods.
  var v = A(); // Instance #1 of A
  var w = A(); // Instance #2 of A
  var y = w;
  x = w.baz;

  // These closures refer to the same instance (#2),
  // so they're equal.
  assert(y.baz == x);

  // These closures refer to different instances,
  // so they're unequal.
  assert(v.baz != w.baz);
}

返回值

foo() {}
assert(foo() == null);

運(yùn)算符

Dart定義下表中顯示的運(yùn)算符。您可以覆蓋許多運(yùn)算符,如在 可重寫運(yùn)算符

描述 運(yùn)算符
一元后綴 expr++ expr-- () [] . ?.
一元前綴 -expr !expr ~expr ++expr --expr
* / % ~/
添加 + -
位移 << >> >>>
按位與 &
按位異或 ^
按位或 |
大小和類型測試 >= > <= < as is is!
相等性 == !=
邏輯與 &&
邏輯或 ||
非空 ??
?表達(dá)式 expr1 ? expr2 : expr3
級聯(lián) ..
再運(yùn)算 = *= /= += -= &= ^= etc.

警告: 運(yùn)算符優(yōu)先級是Dart解析器行為。有關(guān)明確的規(guī)則,請參閱Dart語言規(guī)范中的語法

使用運(yùn)算符時(shí),可以創(chuàng)建表達(dá)式。以下是運(yùn)算符表達(dá)式的一些示例:

a++
a + b
a = b
a == b
c ? a : b
a is T

運(yùn)算符表中,每個(gè)運(yùn)算符的優(yōu)先級高于其后的行中的運(yùn)算符。例如,乘法運(yùn)算符的%優(yōu)先級高于(因此之前執(zhí)行)等于運(yùn)算符==,它的優(yōu)先級高于邏輯AND運(yùn)算符&&。該優(yōu)先級意味著以下兩行代碼執(zhí)行相同的方式:

// Parentheses improve readability.
if ((n % i == 0) && (d % i == 0)) ...

// Harder to read, but equivalent.
if (n % i == 0 && d % i == 0) ...

警告: 對于處理兩個(gè)操作數(shù)的運(yùn)算符,最左邊的操作數(shù)確定使用哪個(gè)對象的運(yùn)算符。例如,如果您有Vector對象和Point對象,則aVector + aPoint使用Vector對象的+。

算術(shù)運(yùn)算符

Dart支持通常的算術(shù)運(yùn)算符,如下表所示。

Operator Meaning
+
-expr 負(fù)號
* 乘法
/ 除法
~/ 整除
% 獲取整數(shù)除法的余數(shù)(模數(shù))

例:

assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5); // Result is a double
assert(5 ~/ 2 == 2); // Result is an int
assert(5 % 2 == 1); // Remainder

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

Dart還支持前綴和后綴增量和減量運(yùn)算符。

操作者 含義
++var var = var + 1(表達(dá)式值是var + 1)
var++ var = var + 1(表達(dá)式值是var)
--var var = var – 1(表達(dá)式值是var – 1)
var-- var = var – 1(表達(dá)式值是var)
var a, b;

a = 0;
b = ++a; // Increment a before b gets its value.
assert(a == b); // 1 == 1

a = 0;
b = a++; // Increment a AFTER b gets its value.
assert(a != b); // 1 != 0

a = 0;
b = --a; // Decrement a before b gets its value.
assert(a == b); // -1 == -1

a = 0;
b = a--; // Decrement a AFTER b gets its value.
assert(a != b); // -1 != 0

相等和關(guān)系運(yùn)算符

下表列出了相等運(yùn)算符和關(guān)系運(yùn)算符的含義。

操作者 含義
== 等于; 見下面的討論
!= 不相等
> 比...更棒
< 少于
>= 大于或等于
<= 小于或等于

要測試兩個(gè)對象x和y是否表示相同的事物,請使用 ==運(yùn)算符。(在極少數(shù)情況下,您需要知道兩個(gè)對象是否是完全相同的對象,請使用相同的() 函數(shù)。)以下是==運(yùn)算符的工作方式:

  1. 如果xy為null,則如果兩者都為null則返回true;如果只有一個(gè)為null,則返回false。

  2. 返回方法調(diào)用的結(jié)果 。(這是正確的,運(yùn)算符,例如在第一個(gè)操作數(shù)上調(diào)用的方法。您甚至可以覆蓋許多運(yùn)算符,包括,正如您在Overridable運(yùn)算符中看到的那樣 。)*x*.==(*y*)``==``==

這是使用每個(gè)相等和關(guān)系運(yùn)算符的示例:
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);

類型檢測運(yùn)算符

使用as,is和is!運(yùn)算符可以方便地在運(yùn)行時(shí)檢查類型。

操作者 含義
as Typecast(也用于指定庫前綴)
is 如果對象具有指定的類型,則為True
is! 如果對象具有指定的類型,則返回false

obj is T如果obj實(shí)現(xiàn)了指定的接口,則結(jié)果為true T。例如,obj is Object總是如此。
使用as運(yùn)算符將對象強(qiáng)制轉(zhuǎn)換為特定類型。通常,您應(yīng)該使用它作為is對使用該對象的表達(dá)式后跟對象的測試的簡寫。例如,請考慮以下代碼:

if (emp is Person) {
  // Type check
  emp.firstName = 'Bob';
}

您可以使用as運(yùn)算符縮短代碼:

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

注意: 代碼不相同。如果emp為null或不是Person,則第一個(gè)示例(with is)不執(zhí)行任何操作; 第二個(gè)(帶as)拋出一個(gè)異常。

賦值操作符

如您所見,您可以使用=運(yùn)算符分配值。要僅在變量為null時(shí)分配,請使用??=運(yùn)算符,如下,如果為null就執(zhí)行f

// Assign value to a
a = value;
// Assign value to b if b is null; otherwise, b stays the same
b ??= value;

復(fù)合賦值運(yùn)算符,例如+=將操作與賦值組合在一起。

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

以下是復(fù)合賦值運(yùn)算符的工作原理:

復(fù)合賦值 等價(jià)表達(dá)
對于運(yùn)營商op: a op= b a = a op b
例: a += b a = a + b

以下示例使用賦值和復(fù)合賦值運(yùn)算符:

var a = 2; // Assign using =
a *= 3; // Assign and multiply: a = a * 3
assert(a == 6);

邏輯運(yùn)算符

您可以使用邏輯運(yùn)算符反轉(zhuǎn)或組合布爾表達(dá)式

操作者 含義
!expr 反轉(zhuǎn)以下表達(dá)式(將false更改為true,反之亦然)
|| 邏輯或
&& 邏輯AND

以下是使用邏輯運(yùn)算符的示例:

if (!done && (col == 0 || col == 3)) {
  // ...Do something...
}

按位和移位運(yùn)算符

您可以在Dart中操縱數(shù)字的各個(gè)位。通常,您將使用這些按位和移位運(yùn)算符和整數(shù)。

操作者 含義
&
|
^ 異或
~expr 一元逐位補(bǔ)碼(0s變?yōu)?s; 1s變?yōu)?s)
<< 向左位移
>> 向右位移

這是使用按位和移位運(yùn)算符的示例:

final value = 0x22;
final bitmask = 0x0f;

assert((value & bitmask) == 0x02); // AND
assert((value & ~bitmask) == 0x20); // AND NOT
assert((value | bitmask) == 0x2f); // OR
assert((value ^ bitmask) == 0x2d); // XOR
assert((value << 4) == 0x220); // Shift left
assert((value >> 4) == 0x02); // Shift right

條件表達(dá)式

Dart有兩個(gè)運(yùn)算符,可以讓您簡明地計(jì)算可能需要if-else語句的表達(dá)式:

condition ? expr1 : expr2

如果condition為true,則計(jì)算expr1(并返回其值); 否則,計(jì)算并返回expr2的值。

`expr1 ?? expr2`

如果expr1為非null,則返回其值; 否則,計(jì)算并返回expr2的值。
當(dāng)您需要根據(jù)布爾表達(dá)式分配值時(shí),請考慮使用?:

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

如果布爾表達(dá)式測試為null,請考慮使用??。

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

前面的例子至少可以用其他兩種方式編寫,但不夠簡潔:

// Slightly longer version uses ?: operator.
String playerName(String name) => name != null ? name : 'Guest';

// Very long version uses if-else statement.
String playerName(String name) {
  if (name != null) {
    return name;
  } else {
    return 'Guest';
  }
}

級聯(lián)符號..

(Cascades)級聯(lián)符號 .. 允許您對同一對象進(jìn)行一系列操作。除了函數(shù)調(diào)用,您還可以訪問同一對象上的字段。這通常可以為您節(jié)省創(chuàng)建臨時(shí)變量的步驟,并允許您編寫更多流暢的代碼。

請考慮以下代碼:

querySelector('#confirm') // Get an object.
  ..text = 'Confirm' // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));

第一個(gè)方法調(diào)用,querySelector()返回一個(gè)選擇器對象。級聯(lián)表示法后面的代碼對此選擇器對象進(jìn)行操作,忽略可能返回的任何后續(xù)值。
前面的例子相當(dāng)于:

var button = querySelector('#confirm');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));

您也可以嵌套您的級聯(lián)。例如:

final addressBook = (AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();

小心在返回實(shí)際對象的函數(shù)上構(gòu)造級聯(lián)。例如,以下代碼失敗:

var sb = StringBuffer();
sb.write('foo')
  ..write('bar'); // Error: method 'write' isn't defined for 'void'.
//返回為void的不能再構(gòu)造級聯(lián)
.setTitle
.setView
.setIcon

該sb.write()調(diào)用無返回值,不能構(gòu)造void的級聯(lián)。

其他運(yùn)算符

在其他示例中,您會(huì)看到了大多數(shù)剩余的運(yùn)算符:

操作者 名稱 含義
() 功能應(yīng)用 表示函數(shù)調(diào)用
[] 列表訪問 引用列表中指定索引處的值
. 成員訪問 指表達(dá)式的屬性; 示例:從表達(dá)式中foo.bar選擇屬性barfoo
?. 有條件的成員訪問權(quán)限 比如.,但最左邊的操作數(shù)可以為null; 示例:從表達(dá)式中foo?.bar選擇屬性bar,foo除非foo為null(在這種情況下,值為foo?.barnull)

控制流程語句

您可以使用以下任一方法控制Dart代碼的流程:

  • if 和 else
  • for 循環(huán)
  • while和do- while循環(huán)
  • break 和 continue
  • switch 和 case
  • assert
    您還可以使用try-catch和影響控制流throw,如異常中所述

If and else

Dart支持if帶有可選else語句的語句,如下一個(gè)示例所示。另見條件表達(dá)式

if (isRaining()) {
  you.bringRainCoat();
} else if (isSnowing()) {
  you.wearJacket();
} else {
  car.putTopDown();
}
for循環(huán)

您可以使用標(biāo)準(zhǔn)for循環(huán)進(jìn)行迭代。例如:

var message = StringBuffer('Dart is fun');
for (var i = 0; i < 5; i++) {
  message.write('!');
}

Dart for循環(huán)內(nèi)部的閉包捕獲了索引的值,避免了JavaScript中常見的陷阱。例如,考慮:

var callbacks = [];
for (var i = 0; i < 2; i++) {
  callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());

如預(yù)期一樣,會(huì)輸出0然后1。相反,在js里會(huì)打印出2個(gè)2。
如果要迭代的對象是Iterable,則可以使用 forEach()方法。forEach()如果您不需要知道當(dāng)前的迭代計(jì)數(shù)器,則使用是一個(gè)不錯(cuò)的選擇:

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

像List和Set這樣for-in的可迭代類也支持迭代的形式 :

var collection = [0, 1, 2];
for (var x in collection) {
  print(x); // 0 1 2
}
While and do-while

一個(gè)while循環(huán)在執(zhí)行循環(huán)內(nèi)的邏輯之前,先計(jì)算表達(dá)式是否符合條件:

while (!isDone()) {
  doSomething();
}

一個(gè)while循環(huán)先計(jì)算表達(dá)式是否符合條件,然后執(zhí)行循環(huán)內(nèi)的邏輯:

do {
  printLine();
} while (!atEndOfPage());
Break and continue

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

while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}

使用continue跳到下一個(gè)循環(huán)迭代:

for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}

如果您使用Iterable(如列表或集合),則可能會(huì)以不同的方式編寫該示例 :

candidates
    .where((c) => c.yearsExperience >= 5)
    .forEach((c) => c.interview());
Switch and case

Dart中的switch語句支持整數(shù),字符串或,使用==來比較的編譯時(shí)常量。比較對象必須都是同一個(gè)類的實(shí)例(而不是其任何子類型),并且該類不能覆蓋==枚舉類型switch語句也支持。

注意: Dart中的Switch語句適用于有限的情況,例如interpreters 或scanners。

每個(gè)非空case子句break通常以語句結(jié)束。其他有效的方式來結(jié)束一個(gè)非空的case條目是continue, throw或return。
default當(dāng)沒有case子句匹配時(shí),使用子句執(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();
}

以下示例省略break了case子句中的語句,從而產(chǎn)生錯(cuò)誤(如果當(dāng)前case擁有語句,不寫break的話,會(huì)報(bào)錯(cuò)):

var command = 'OPEN';
switch (command) {
  case 'OPEN':
    executeOpen();
    // ERROR: Missing break

  case 'CLOSED':
    executeClosed();
    break;
}

但是,Dart確實(shí)支持空case句子,允許一種形式的落空(向下執(zhí)行):

var command = 'CLOSED';
switch (command) {
  case 'CLOSED': // Empty case falls through.
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

如果你真的想要落空條目,你可以使用一個(gè)continue聲明和一個(gè)標(biāo)簽:

var command = 'CLOSED';
switch (command) {
  case 'CLOSED':
    executeClosed();
    continue nowClosed;
  // Continues executing at the nowClosed label.

  nowClosed://這里是一個(gè)標(biāo)簽,可以寫任意標(biāo)識符
  case 'NOW_CLOSED':
    // Runs for both CLOSED and NOW_CLOSED.
    executeNowClosed();
    break;
}

一個(gè)case條目可以有局部變量,作用域是內(nèi)部的條目的范圍。

斷言

assert如果布爾條件為false,斷言語句中斷正常執(zhí)行,以下為例:

// Make sure the variable has a non-null value.
assert(text != null);

// Make sure the value is less than 100.
assert(number < 100);

// Make sure this is an https URL.
assert(urlString.startsWith('https'));

注意: 斷言語句對生產(chǎn)代碼沒有影響; 他們只是為了發(fā)展。Flutter在調(diào)試模式下啟用斷言 僅限開發(fā)的工具(如dartdevc) 通常默認(rèn)支持?jǐn)嘌浴R恍┕ぞ撸?a target="_blank">dart和dart2js, 通過命令行標(biāo)志支持?jǐn)嘌裕?code>--enable-asserts。

要將消息附加到斷言,請?zhí)砑右粋€(gè)字符串作為第二個(gè)參數(shù)。

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

第一個(gè)參數(shù)assert可以是任何解析為布爾值的表達(dá)式。如果表達(dá)式的值為true,則斷言成功并繼續(xù)執(zhí)行。如果為false,則斷言失敗并拋出異常( AssertionError)。

Exceptions

你的Dart代碼可以拋出和捕捉異常。異常是錯(cuò)誤,表示發(fā)生了意外的事情。如果沒有捕獲到異常,引發(fā)異常的隔離會(huì)掛起,通常隔離及其程序會(huì)終止。

與Java相比,Dart的所有異常都是未經(jīng)檢查的異常。方法不會(huì)聲明它們可能引發(fā)的異常,并且您不需要捕獲任何異常。

Dart提供了ExceptionError 類型,以及許多預(yù)定義的子類型。當(dāng)然,您可以定義自己的例外情況。但是,Dart程序可以拋出任何非null對象 - 不僅僅是Exception和Error對象 - 作為異常。

Throw

以下是拋出或引發(fā)異常的示例:

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

你也可以拋出任意對象:

throw 'Out of llamas!';

注意:生產(chǎn)質(zhì)量代碼通常會(huì)拋出實(shí)現(xiàn)錯(cuò)誤異常的類型 。
因?yàn)閽伋霎惓J且粋€(gè)表達(dá)式,所以可以在=>語句中以及允許表達(dá)式的任何其他地方拋出異常:

void distanceTo(Point other) => throw UnimplementedError();

Catch

要處理可能拋出多種類型異常的代碼,可以指定多個(gè)catch子句。與拋出對象的類型匹配的第一個(gè)catch子句處理異常。如果catch子句未指定類型,則該子句可以處理任何類型的拋出對象:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  buyMoreLlamas();
}

正如上面的代碼所示,您可以使用oncatch或兩者兼而有之。使用on時(shí)需要指定異常類型。使用catch時(shí),你的異常處理程序需要異常對象。

要處理可能拋出多種類型異常的代碼,可以指定多個(gè)catch子句。與拋出對象的類型匹配的第一個(gè)catch子句處理異常。如果catch子句未指定類型,則該子句可以處理任何類型的拋出對象:

try {
  breedMoreLlamas();
} on OutOfLlamasException {
  // A specific exception
  buyMoreLlamas();
} on Exception catch (e) {
  // Anything else that is an exception
  print('Unknown exception: $e');
} catch (e) {
  // No specified type, handles all
  print('Something really unknown: $e');
}

正如上面的代碼所示,您可以使用oncatch或兩者兼而有之。使用on時(shí)需要指定異常類型。使用catch時(shí),你的異常處理程序需要異常對象。

您可以指定一個(gè)或兩個(gè)參數(shù)catch()。第一個(gè)是拋出的異常,第二個(gè)是堆棧跟蹤(StackTrace對象)。

try {
  // ···
} on Exception catch (e) {
  print('Exception details:\n $e');
} catch (e, s) {
  print('Exception details:\n $e');
  print('Stack trace:\n $s');
}

要部分處理異常,同時(shí)允許它傳播,請使用rethrow關(guān)鍵字。

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

無論是否拋出異常,要確保某些代碼運(yùn)行,請使用finally子句。如果沒有catch子句匹配該異常,則在finally子句運(yùn)行后傳播異常:

try {
  breedMoreLlamas();
} finally {
  // Always clean up, even if an exception is thrown.
  cleanLlamaStalls();
}

該finally子句在任何匹配的catch子句之后運(yùn)行:

try {
  breedMoreLlamas();
} catch (e) {
  print('Error: $e'); // Handle the exception first.
} finally {
  cleanLlamaStalls(); // Then clean up.
}

閱讀 dart之旅的Exception部分,了解更多相關(guān)信息 。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。