這篇文章將會(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)置類型 是String
,List
和bool
。
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)鍵字
public
,protected
和private
。如果標(biāo)識符以下劃線(_)開頭,則它對其庫是私有的。有關(guān)詳細(xì)信息,請參閱 庫和可見性。 - 標(biāo)識符可以以字母或下劃線(_)開頭,后跟這些字符加數(shù)字的任意組合。
- Dart可以使用表達(dá)式(具有運(yùn)行時(shí)值)和 語句(不具有)。例如,條件表達(dá)式
condition ? expr1 : expr2
的值為expr1
或expr2
。將其與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)的更新,有限的保留字。不能使用
await
或yield
作為任何函數(shù)體中的標(biāo)識符標(biāo)記async
,async*
或sync*
。
表中的所有其他單詞都是保留字,不能是標(biāo)識符。
變量
這是創(chuàng)建變量并初始化它的示例:
var name = 'Bob' ;
變量存儲(chǔ)引用。名為name的變量指向String值為“Bob” 的對象。
name
推斷變量的類型String
,但您可以通過指定它來更改該類型。如果對象不限于單一類型,請按照設(shè)計(jì)準(zhǔn)則指定Object
或dynamic
類型 。
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ì)信息,請參閱不要冗余地使用const。const``baz
您可以更改非final,非const變量的值,即使它曾經(jīng)有一個(gè)const值:
foo = [1, 2, 3]; // Was const []
您無法更改const變量的值:
baz = [ 42 ]; //錯(cuò)誤:無法為常量變量賦值。
有關(guān)使用const
創(chuàng)建常量值的更多信息,請參閱 Lists,Maps和Classes。
內(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è)int
和double
的亞型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.
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
類型的 DartMap<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信息。在codeUnitAt
和codeUnit
屬性返回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ò)。
requared在mate包中定義。可以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)算符的工作方式:
如果x或y為null,則如果兩者都為null則返回true;如果只有一個(gè)為null,則返回false。
返回方法調(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提供了Exception和Error 類型,以及許多預(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();
}
正如上面的代碼所示,您可以使用on
或catch
或兩者兼而有之。使用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');
}
正如上面的代碼所示,您可以使用on
或catch
或兩者兼而有之。使用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)信息 。