這篇文章將會向你展示如何使用Dart的每一個知識點,包括變量,操作符,類,類庫,但這是在你已經有一個其他語言的編碼經驗的前提下。
為了學習Dart更多關于Dart的核心類庫,請查看A Tour of the Dart Libraries,當你想知道更多語言特征,挺查閱Dart language specification
你可以通過DartPad 來嘗試運行Dart代碼:Open DartPad
一個基本的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應用程序的內容:
// This is a comment.
單行注釋。Dart還支持多行和文檔注釋。有關詳情,請參閱注釋
int
整數(shù)類型。一些其他的內置類型 是String,List和bool。
42
一個整數(shù)字面值,這是一個編譯時常量。
print()
一個方便的輸出函數(shù)。
'...' (or "...")
字符串字面值。
$variableName(或)${expression}
字符串插值:包括字符串字面值內部的變量或表達式的字符串。有關更多信息,請參閱 字符串。
main()
一個特殊的頂級(top)的必須的(requared)app應用的入口函數(shù),有關更多信息,請參閱 main()函數(shù)。
var
一種聲明變量而不指定其類型的方法。
重要的概念
當您了解Dart語言時,請記住以下事實和概念:
- 變量所指向的所有值都是對象,每個對象都是一個類的實例。數(shù)字,函數(shù)(函數(shù)也是一個變量)和
null對象等。所有對象都繼承自Object類。 - 盡管Dart是強類型的,但類型聲明是可選的,因為Dart可以推斷類型。在上面的代碼中,
number推斷為類型int。如果要明確說明不需要任何類型,請 使用特殊類型dynamic。 - Dart支持泛型類型,如List<int>(整數(shù)List)或List<dynamic>(任何類型的對象List)。
- Dart支持頂級函數(shù)(例如main()),以及綁定到類或對象的函數(shù)(分別是靜態(tài)和實例方法)。您還可以在函數(shù)內創(chuàng)建函數(shù)(嵌套函數(shù)或本地函數(shù))。
- 類似地,Dart支持頂級變量,以及綁定到類或對象的變量(靜態(tài)和實例變量)。實例變量有時稱為字段或屬性。
- 與Java,Dart不具備關鍵字
public,protected和private。如果標識符以下劃線(_)開頭,則它對其庫是私有的。有關詳細信息,請參閱 庫和可見性。 - 標識符可以以字母或下劃線(_)開頭,后跟這些字符加數(shù)字的任意組合。
- Dart可以使用表達式(具有運行時值)和 語句(不具有)。例如,條件表達式
condition ? expr1 : expr2的值為expr1或expr2。將其與if-else語句進行比較,語句沒有任何值。語句通常包含一個或多個表達式,但表達式不能直接包含語句。 - Dart工具可以報告兩種問題:警告和錯誤。警告只是表明您的代碼可能無法正常工作,但它們不會阻止您的程序執(zhí)行。錯誤可以是編譯時或運行時。編譯時錯誤會阻止代碼執(zhí)行; 運行時錯誤導致 代碼執(zhí)行時引發(fā)異常。
關鍵字
下表列出了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的任務,這些關鍵字在大多數(shù)地方都是有效的標識符,但它們不能用作類或類型名稱,也不能用作導入前綴。
- 帶有上標3的單詞是與Dart 1.0發(fā)布后添加的異步支持相關的更新,有限的保留字。不能使用
await或yield作為任何函數(shù)體中的標識符標記async,async*或sync*。
表中的所有其他單詞都是保留字,不能是標識符。
變量
這是創(chuàng)建變量并初始化它的示例:
var name = 'Bob' ;
變量存儲引用。名為name的變量指向String值為“Bob” 的對象。
name推斷變量的類型String,但您可以通過指定它來更改該類型。如果對象不限于單一類型,請按照設計準則指定Object或dynamic類型 。
dynamic name = 'Bob' ;
另一種選擇是顯式聲明類型:
String name = 'Bob' ;
注意: 此頁面遵循 風格指南建議 使用
var,而不是指定類型,用于局部變量。
默認值
未初始化的變量的初始值為null。即使是具有數(shù)字類型的變量最初也是null,因為數(shù)字 - 就像Dart中的其他所有都是對象。
int lineCount ;
assert (lineCount == null );
注意:生產環(huán)境代碼中將忽略assert() 調用。在開發(fā)期間, 除非條件為真,否則拋出異常。有關詳細信息,請參閱斷言。
Final and const
如果您從未打算更改變量,請使用final或const代替var或替代類型。最終變量只能設置一次; const變量是編譯時常量。(Const變量是隱式final的。)final的頂級或類變量在第一次使用時被初始化。
以下是創(chuàng)建和設置最終變量的示例:
final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
您無法更改最終變量的值:
name = 'Alice' ; //錯誤:最終變量只能設置一次。
使用const為您要為變量的編譯時間常數(shù)。如果const變量在類級別,請聲明為static const。在聲明變量的地方,將值設置為編譯時常量,例如數(shù)字或字符串字面值,const變量或對常數(shù)進行算術運算的結果:
const bar = 1000000; // 壓力單位 (dynes/cm2)
const double atm = 1.01325 * bar; // 標準大氣壓
該const關鍵字不只是聲明常數(shù)變量。您還可以使用它來創(chuàng)建常量值,以及聲明創(chuàng)建常量值的構造函數(shù)。任何變量都可以具有常量值。
var foo = const [];
final bar = const [];
const baz = []; //相當于`const []`
您可以省略聲明const的初始化表達式,如上所述。有關詳細信息,請參閱不要冗余地使用const。const``baz
您可以更改非final,非const變量的值,即使它曾經有一個const值:
foo = [1, 2, 3]; // Was const []
您無法更改const變量的值:
baz = [ 42 ]; //錯誤:無法為常量變量賦值。
有關使用const創(chuàng)建常量值的更多信息,請參閱 Lists,Maps和Classes。
內置類型
Dart語言特別支持以下類型:
- numbers
- strings
- booleans
- lists (also known as arrays)
- sets
- maps
- runes (for expressing Unicode characters in a string)
- symbols
您可以使用字面值初始化任何這些特殊類型的對象。例如,'this is a string'是一個字符串字面值,true是一個布爾字面值。
因為Dart中的每個變量都引用一個對象 - 一個類的實例 - 您通常可以使用構造函數(shù)來初始化變量。一些內置類型有自己的構造函數(shù)。例如,您可以使用Map()構造函數(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位(雙精度)浮點數(shù),由IEEE 754標準規(guī)定。
這兩個int和double的亞型num。 num類型支持基本的運算符,如+, - ,/和*,以及abs(),ceil()和floor()其他方法已在其中定義。(按位運算符,例如>>,在int類中定義。)如果num及其子類型沒有您要查找的內容,則 dart:math庫可能會定義。
整數(shù)是沒有小數(shù)點的數(shù)字。以下是定義整型字面值的一些示例:
var x = 1;
var hex = 0xDEADBEEF;
如果數(shù)字包含小數(shù),則為雙精度數(shù)。以下是定義雙精度字面值的一些示例:
var y = 1.1;
var exponents = 1.42e5;
從Dart 2.1開始,必要時整型字面值會自動轉換為雙精度數(shù):
double z = 1; // Equivalent to double z = 1.0.
版本說明: 在Dart 2.1之前,在雙精度數(shù)變量賦值為整型字面值是錯誤的。
以下是將字符串轉換為數(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(|)運算符。例如:
assert((3 << 1) == 6); // 0011 << 1 == 0110
assert((3 >> 1) == 1); // 0011 >> 1 == 0001
assert((3 | 4) == 7); // 0011 | 0100 == 0111
字面值數(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.";
您可以使用表達式將表達式的值放在字符串中 。如果表達式是標識符,則可以跳過{}。要獲取與對象相對應的字符串,Dart會調用該對象的方法。${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!');
注: 在==兩個物體操作測試是否是等價的。如果兩個字符串包含相同的代碼單元序列,則它們是等效的。(這一點和java是不同的,java,String的==運算符,只有當?shù)刂芬粯樱置嬷狄粯?,才能使相等的,dart String 的== 相當于java String的equal)
您可以使用相鄰的字符串字面值或+ 運算符來連接字符串:
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.';
有關如何在字符串中表示Unicode字符的詳細信息,請參閱Runes。
字符串字面值是編譯時常量,因為任何插值表達式是一個編譯時常量,其值為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';
有關使用字符串的更多信息,請參閱 字符串和正則表達式。
Booleans
為了表示布爾值,Dart具有一個名為的類型bool。只有兩個對象具有bool類型:boolean 字面值 true和false,它們都是編譯時常量。
Dart的類型安全意味著你不能使用像或 那樣的代碼,如下:
if (nonbooleanValue)
assert (nonbooleanValue)
應該明確能計算出值:
// 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ù)組字面值。這是一個簡單的Dart List:
var list = [1, 2, 3];
注意: Dart推斷出
list有類型List<int>。如果嘗試將非整數(shù)對象添加到此List,則分析器或運行時會引發(fā)錯誤。有關更多信息,請閱讀 類型推斷。
List使用從零開始的索引,list.length - 1是最后一個元素的索引。您可以獲得List的長度并像在JavaScript中一樣引用List元素:
var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);
list[1] = 1;
assert(list[1] == 1);
要創(chuàng)建一個編譯時常量const的List,請在List文字前添加const:
var constantList = const [1, 2, 3];
// constantList[1] = 1; // Uncommenting this causes an error.
List類型有許多方便的方法來操作List。有關List的更多信息,請參閱泛型和 集合。
Sets
Dart中的set是一組無序的獨特item集合。對集合的Dart支持由set 字面值和Set類型提供。
這是一個簡單的Dart集,使用set 字面值創(chuàng)建:
var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};
Dart推斷出
halogens具有該類型Set<String>。如果您嘗試向集合中添加錯誤類型的值,則分析器或運行時會引發(fā)錯誤。有關更多信息,請閱讀 類型推斷。
要創(chuàng)建一個空集,請使用{}前面帶有類型參數(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)先級靠前,因此{}默認為Map類型。如果您忘記了類型注釋{}或它所分配的變量,則Dart會創(chuàng)建一個類型的對象Map<dynamic, dynamic>。
使用add()或addAll()方法將項添加到現(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);
要創(chuàng)建一個編譯時常量const的集合,請在set literal之前添加const:
final constantSet = const {
'fluorine',
'chlorine',
'bromine',
'iodine',
'astatine',
};
// constantSet.add('helium'); // Uncommenting this causes an error.
Maps
通常,映射是關聯(lián)鍵和值的對象。鍵和值都可以是任何類型的對象。每個鍵只出現(xiàn)一次,但您可以多次使用相同的值。Map的Dart支持由Map字面值和Map類型提供。
這里有幾個簡單的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>。如果您嘗試將錯誤類型的值添加到任一映射,則分析器或運行時會引發(fā)錯誤。有關更多信息,請閱讀 類型推斷。
您可以使用Map構造函數(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關鍵字是可選的。有關詳細信息,請參閱使用構造函數(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中的鍵,則會得到null作為回報:
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);
使用.length得到的映射中的鍵值對的數(shù)量:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);
要創(chuàng)建一個編譯時常量const的Map,請在Map字面值之前添加const:
有關Map的更多信息,請參閱 泛型和 Map。
Runes
在Dart中,Runes是字符串的UTF-32表達。
Unicode為世界上所有書寫系統(tǒng)中使用的每個字母,數(shù)字和符號定義唯一的數(shù)值。由于Dart字符串是UTF-16代碼單元的序列,因此在字符串中表示32位Unicode值需要特殊語法。
表達Unicode代碼點的常用方法是 \uXXXX,XXXX是4位十六進制值。例如,心臟角色(?)是\u2665。要指定多于或少于4個十六進制數(shù)字,請將值放在大括號中。例如,笑的表情符號(??)是\u{1f600}。
該字符串 類有幾個屬性,你可以用它來提取Runes信息。在codeUnitAt和codeUnit屬性返回16位編碼單元。使用該runes屬性獲取字符串的Runes。
以下示例說明了符文,16位代碼單元和32位代碼點之間的關系。
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));
}

注意: 使用列表操作操作符文時要小心。這種方法很容易使字符串解體,具體取決于特定的語言,字符集和操作。有關更多信息,請參閱 如何在Dart中反轉字符串?在Stack Overflow上。
Symbols
Symbol對象表示在Dart程序中聲明的運算符或標識符。您可能永遠不需要使用符號,但它們對于按名稱引用標識符的API非常有用,因為縮小會更改標識符名稱而不會更改標識符符號。要獲取標識符的符號,請使用符號文字,它只是#后跟標識符:(這一段實在不會翻譯了- -)
要獲取標識符的符號,請使用符號文字, #后面跟著標識符:
#radix
#bar
Symbols文字是編譯時常量。
Functions
Dart是一種真正的面向對象語言,因此即使是函數(shù)也是對象并且具有類型Function。 這意味著函數(shù)可以分配給變量或作為參數(shù)傳遞給其他函數(shù)。您也可以調用Dart類的實例,就好像它是一個函數(shù)一樣。有關詳細信息,請參閱Callable classes
以下是實現(xiàn)函數(shù)的示例:
bool isNoble(int atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
雖然Effective Dart建議 為公共API聲明返回值類型,但如果省略類型,該函數(shù)仍然有效:
isNoble(atomicNumber) {
return _nobleGases[atomicNumber] != null;
}
對于只包含一個表達式的函數(shù),可以使用簡寫語法:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
這個 => 是{ return expr; }的速記 . 。有時將=> 表示法稱為箭頭語法。
只有表達式(而不是語句)能夠出現(xiàn)在箭頭(=>)和分號(;)之間。例如,您不能在其中放置if語句,但可以使用條件表達式。
函數(shù)可以有兩種類型的參數(shù):必需和可選。首先列出所需參數(shù),然后列出任何可選參數(shù)。命名的可選參數(shù)也可以標記為@required。有關詳細信息,請參閱下一節(jié)。
可選參數(shù)
可選參數(shù)可以是位置參數(shù),也可以是名稱參數(shù),但不能同時包含
可選的名稱參數(shù)
調用函數(shù)時,可以使用指定名稱參數(shù) 。例如:paramName: value
enableFlags (bold :true ,hidden :false );
定義函數(shù)時,用于 指定名稱參數(shù):{param1, param2, …}
/// Sets the [bold] and [hidden] flags ...
void enableFlags({bool bold, bool hidden}) {...}
Flutter實例創(chuàng)建表達式可能變得復雜,因此窗口小部件構造函數(shù)僅使用命名參數(shù)。這使得實例創(chuàng)建表達式更易于閱讀。
您可以使用@required在任何Dart代碼(不僅僅是Flutter)中注釋命名參數(shù), 以指示它是必需參數(shù)。例如:
const Scrollbar({Key key, @required Widget child})
當一個Scrollbar構造,當必要參數(shù)缺少時,編譯器會報錯。
requared在mate包中定義??梢?code>package:meta/meta.dart直接導入 ,也可以導入另一個導出的包 meta,例如Flutter package:flutter/material.dart。
可選的位置參數(shù)
包裝一組函數(shù)參數(shù)將[]它們標記為可選的位置參數(shù):
String say(String from, String msg, [String device]) {
var result = '$from says $msg';
if (device != null) {
result = '$result with a $device';
}
return result;
}
這是一個在沒有可選參數(shù)的情況下調用此函數(shù)的示例:
assert(say('Bob', 'Howdy') == 'Bob says Howdy');
以下是使用第三個參數(shù)調用此函數(shù)的示例:
assert(say('Bob', 'Howdy', 'smoke signal') ==
'Bob says Howdy with a smoke signal');
默認參數(shù)值
您的函數(shù)可用于=定義命名和位置參數(shù)的默認值。默認值必須是編譯時常量。如果未提供默認值,則默認值為null。
以下是為命名參數(shù)設置默認值的示例:
/// 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ù)。該支持可能已被棄用,因此我們建議您 使用=指定默認值。
下一個示例顯示如何設置位置參數(shù)的默認值:
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作為默認值傳遞。以下示例定義了一個函數(shù),該函數(shù)doStuff()指定參數(shù)的默認List和list 參數(shù)的默認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ù)
每個應用程序都必須具有頂級main()功能,該功能用作應用程序的入口點。該main()函數(shù)返回void并具有List<String>參數(shù)的可選參數(shù)。
以下main()是Web應用程序功能的示例:
void main() {
querySelector('#sample_text_id')
..text = 'Click me!'
..onClick.listen(reverseText);
}
注意:
..前面代碼中 的語法稱為級聯(lián)。使用級聯(lián),您可以對單個對象的成員執(zhí)行多個操作。
以下main()是帶參數(shù)的命令行應用程序的函數(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ù)傳遞給另一個函數(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ù)。更多關于下一節(jié)的內容。
匿名函數(shù)
大多數(shù)函數(shù)都被命名,例如main()或printElement()。您還可以創(chuàng)建一個名為匿名函數(shù)的無名函數(shù),有時也可以創(chuàng)建一個lambda或閉包。您可以為變量分配匿名函數(shù),以便例如可以在集合中添加或刪除它。
匿名函數(shù)看起來類似于命名函數(shù) - 零個或多個參數(shù),在逗號和括號之間用逗號和可選類型注釋分隔。
后面的代碼塊包含函數(shù)的主體:
([[Type] param1[, …]]) {
codeBlock;
};
以下示例使用無類型參數(shù)item定義匿名函數(shù),為List中的每個項調用的函數(shù)將打印一個包含指定索引處的值的字符串。
var list = ['apples', 'bananas', 'oranges'];
list.forEach((item) {
print('${list.indexOf(item)}: $item');
});
如果函數(shù)只包含一個語句,則可以使用箭頭表示法縮短它。
list.forEach(
(item) => print('${list.indexOf(item)}: $item'));
作用域
Dart是有作用域的語言,這意味著變量的范圍是靜態(tài)確定的,只需通過代碼的布局。您可以“向外跟隨花括號”以查看變量是否在范圍內。
以下是每個范圍級別包含變量的嵌套函數(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()每個級別的變量,一直到頂級。
閉包
一個閉包是能夠訪問在其作用域的變量的函數(shù)的對象,即使當函數(shù)用于其原來的范圍之外。
函數(shù)可以關閉周圍范圍中定義的變量。在以下示例中,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)方法和實例方法的相等性的示例:
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);
運算符
Dart定義下表中顯示的運算符。您可以覆蓋許多運算符,如在 可重寫運算符。
| 描述 | 運算符 |
|---|---|
| 一元后綴 | expr++ expr-- () [] . ?. |
| 一元前綴 | -expr !expr ~expr ++expr --expr |
| 乘 | * / % ~/ |
| 添加 | + - |
| 位移 | << >> >>> |
| 按位與 | & |
| 按位異或 | ^ |
| 按位或 | | |
| 大小和類型測試 | >= > <= < as is is! |
| 相等性 | == != |
| 邏輯與 | && |
| 邏輯或 | || |
| 非空 | ?? |
| ?表達式 | expr1 ? expr2 : expr3 |
| 級聯(lián) | .. |
| 再運算 | = *= /= += -= &= ^= etc. |
警告: 運算符優(yōu)先級是Dart解析器行為。有關明確的規(guī)則,請參閱Dart語言規(guī)范中的語法
使用運算符時,可以創(chuàng)建表達式。以下是運算符表達式的一些示例:
a++
a + b
a = b
a == b
c ? a : b
a is T
在運算符表中,每個運算符的優(yōu)先級高于其后的行中的運算符。例如,乘法運算符的%優(yōu)先級高于(因此之前執(zhí)行)等于運算符==,它的優(yōu)先級高于邏輯AND運算符&&。該優(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) ...
警告: 對于處理兩個操作數(shù)的運算符,最左邊的操作數(shù)確定使用哪個對象的運算符。例如,如果您有Vector對象和Point對象,則aVector + aPoint使用Vector對象的+。
算術運算符
Dart支持通常的算術運算符,如下表所示。
| Operator | Meaning |
|---|---|
| + | 加 |
| – | 減 |
| -expr | 負號 |
| * | 乘法 |
| / | 除法 |
| ~/ | 整除 |
| % | 獲取整數(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還支持前綴和后綴增量和減量運算符。
| 操作者 | 含義 |
|---|---|
| ++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; // 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
相等和關系運算符
下表列出了相等運算符和關系運算符的含義。
| 操作者 | 含義 |
|---|---|
| == | 等于; 見下面的討論 |
| != | 不相等 |
| > | 比...更棒 |
| < | 少于 |
| >= | 大于或等于 |
| <= | 小于或等于 |
要測試兩個對象x和y是否表示相同的事物,請使用 ==運算符。(在極少數(shù)情況下,您需要知道兩個對象是否是完全相同的對象,請使用相同的() 函數(shù)。)以下是==運算符的工作方式:
如果x或y為null,則如果兩者都為null則返回true;如果只有一個為null,則返回false。
返回方法調用的結果 。(這是正確的,運算符,例如在第一個操作數(shù)上調用的方法。您甚至可以覆蓋許多運算符,包括,正如您在Overridable運算符中看到的那樣 。)
*x*.==(*y*)``==``==
這是使用每個相等和關系運算符的示例:
assert(2 == 2);
assert(2 != 3);
assert(3 > 2);
assert(2 < 3);
assert(3 >= 3);
assert(2 <= 3);
類型檢測運算符
使用as,is和is!運算符可以方便地在運行時檢查類型。
| 操作者 | 含義 |
|---|---|
| as | Typecast(也用于指定庫前綴) |
| is | 如果對象具有指定的類型,則為True |
| is! | 如果對象具有指定的類型,則返回false |
obj is T如果obj實現(xiàn)了指定的接口,則結果為true T。例如,obj is Object總是如此。
使用as運算符將對象強制轉換為特定類型。通常,您應該使用它作為is對使用該對象的表達式后跟對象的測試的簡寫。例如,請考慮以下代碼:
if (emp is Person) {
// Type check
emp.firstName = 'Bob';
}
您可以使用as運算符縮短代碼:
(emp as Person).firstName = 'Bob';
注意: 代碼不相同。如果emp為null或不是Person,則第一個示例(with is)不執(zhí)行任何操作; 第二個(帶as)拋出一個異常。
賦值操作符
如您所見,您可以使用=運算符分配值。要僅在變量為null時分配,請使用??=運算符,如下,如果為null就執(zhí)行f
// Assign value to a
a = value;
// Assign value to b if b is null; otherwise, b stays the same
b ??= value;
復合賦值運算符,例如+=將操作與賦值組合在一起。
| = | –= | /= | %= | >>= | ^= |
|---|---|---|---|---|---|
| += | *= | ~/= | <<= | &= | |= |
以下是復合賦值運算符的工作原理:
| 復合賦值 | 等價表達 | |
|---|---|---|
| 對于運營商op: | a op= b | a = a op b |
| 例: | a += b | a = a + b |
以下示例使用賦值和復合賦值運算符:
var a = 2; // Assign using =
a *= 3; // Assign and multiply: a = a * 3
assert(a == 6);
邏輯運算符
您可以使用邏輯運算符反轉或組合布爾表達式
| 操作者 | 含義 |
|---|---|
| !expr | 反轉以下表達式(將false更改為true,反之亦然) |
| || | 邏輯或 |
| && | 邏輯AND |
以下是使用邏輯運算符的示例:
if (!done && (col == 0 || col == 3)) {
// ...Do something...
}
按位和移位運算符
您可以在Dart中操縱數(shù)字的各個位。通常,您將使用這些按位和移位運算符和整數(shù)。
| 操作者 | 含義 |
|---|---|
| & | 和 |
| | | 或 |
| ^ | 異或 |
| ~expr | 一元逐位補碼(0s變?yōu)?s; 1s變?yōu)?s) |
| << | 向左位移 |
| >> | 向右位移 |
這是使用按位和移位運算符的示例:
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
條件表達式
Dart有兩個運算符,可以讓您簡明地計算可能需要if-else語句的表達式:
condition ? expr1 : expr2
如果condition為true,則計算expr1(并返回其值); 否則,計算并返回expr2的值。
`expr1 ?? expr2`
如果expr1為非null,則返回其值; 否則,計算并返回expr2的值。
當您需要根據布爾表達式分配值時,請考慮使用?:
var visibility = isPublic ?'public' :'private' ;
如果布爾表達式測試為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)符號 .. 允許您對同一對象進行一系列操作。除了函數(shù)調用,您還可以訪問同一對象上的字段。這通常可以為您節(jié)省創(chuàng)建臨時變量的步驟,并允許您編寫更多流暢的代碼。
請考慮以下代碼:
querySelector('#confirm') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
第一個方法調用,querySelector()返回一個選擇器對象。級聯(lián)表示法后面的代碼對此選擇器對象進行操作,忽略可能返回的任何后續(xù)值。
前面的例子相當于:
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ù)上構造級聯(lián)。例如,以下代碼失?。?/p>
var sb = StringBuffer();
sb.write('foo')
..write('bar'); // Error: method 'write' isn't defined for 'void'.
//返回為void的不能再構造級聯(lián)
.setTitle
.setView
.setIcon
該sb.write()調用無返回值,不能構造void的級聯(lián)。
其他運算符
在其他示例中,您會看到了大多數(shù)剩余的運算符:
| 操作者 | 名稱 | 含義 |
|---|---|---|
| () | 功能應用 | 表示函數(shù)調用 |
| [] | 列表訪問 | 引用列表中指定索引處的值 |
| . | 成員訪問 | 指表達式的屬性; 示例:從表達式中foo.bar選擇屬性barfoo |
| ?. | 有條件的成員訪問權限 | 比如.,但最左邊的操作數(shù)可以為null; 示例:從表達式中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語句的語句,如下一個示例所示。另見條件表達式。
if (isRaining()) {
you.bringRainCoat();
} else if (isSnowing()) {
you.wearJacket();
} else {
car.putTopDown();
}
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中常見的陷阱。例如,考慮:
var callbacks = [];
for (var i = 0; i < 2; i++) {
callbacks.add(() => print(i));
}
callbacks.forEach((c) => c());
如預期一樣,會輸出0然后1。相反,在js里會打印出2個2。
如果要迭代的對象是Iterable,則可以使用 forEach()方法。forEach()如果您不需要知道當前的迭代計數(shù)器,則使用是一個不錯的選擇:
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
一個while循環(huán)在執(zhí)行循環(huán)內的邏輯之前,先計算表達式是否符合條件:
while (!isDone()) {
doSomething();
}
一個while循環(huán)先計算表達式是否符合條件,然后執(zhí)行循環(huán)內的邏輯:
do {
printLine();
} while (!atEndOfPage());
Break and continue
使用break停止循環(huán):
while (true) {
if (shutDownRequested()) break;
processIncomingRequests();
}
使用continue跳到下一個循環(huán)迭代:
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 and case
Dart中的switch語句支持整數(shù),字符串或,使用==來比較的編譯時常量。比較對象必須都是同一個類的實例(而不是其任何子類型),并且該類不能覆蓋==。 枚舉類型switch語句也支持。
注意: Dart中的Switch語句適用于有限的情況,例如interpreters 或scanners。
每個非空case子句break通常以語句結束。其他有效的方式來結束一個非空的case條目是continue, throw或return。
default當沒有case子句匹配時,使用子句執(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子句中的語句,從而產生錯誤(如果當前case擁有語句,不寫break的話,會報錯):
var command = 'OPEN';
switch (command) {
case 'OPEN':
executeOpen();
// ERROR: Missing break
case 'CLOSED':
executeClosed();
break;
}
但是,Dart確實支持空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;
}
如果你真的想要落空條目,你可以使用一個continue聲明和一個標簽:
var command = 'CLOSED';
switch (command) {
case 'CLOSED':
executeClosed();
continue nowClosed;
// Continues executing at the nowClosed label.
nowClosed://這里是一個標簽,可以寫任意標識符
case 'NOW_CLOSED':
// Runs for both CLOSED and NOW_CLOSED.
executeNowClosed();
break;
}
一個case條目可以有局部變量,作用域是內部的條目的范圍。
斷言
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'));
注意: 斷言語句對生產代碼沒有影響; 他們只是為了發(fā)展。Flutter在調試模式下啟用斷言。 僅限開發(fā)的工具(如dartdevc) 通常默認支持斷言。一些工具,如dart和dart2js, 通過命令行標志支持斷言:
--enable-asserts。
要將消息附加到斷言,請?zhí)砑右粋€字符串作為第二個參數(shù)。
assert(urlString.startsWith('https'),
'URL ($urlString) should start with "https".');
第一個參數(shù)assert可以是任何解析為布爾值的表達式。如果表達式的值為true,則斷言成功并繼續(xù)執(zhí)行。如果為false,則斷言失敗并拋出異常( AssertionError)。
Exceptions
你的Dart代碼可以拋出和捕捉異常。異常是錯誤,表示發(fā)生了意外的事情。如果沒有捕獲到異常,引發(fā)異常的隔離會掛起,通常隔離及其程序會終止。
與Java相比,Dart的所有異常都是未經檢查的異常。方法不會聲明它們可能引發(fā)的異常,并且您不需要捕獲任何異常。
Dart提供了Exception和Error 類型,以及許多預定義的子類型。當然,您可以定義自己的例外情況。但是,Dart程序可以拋出任何非null對象 - 不僅僅是Exception和Error對象 - 作為異常。
Throw
以下是拋出或引發(fā)異常的示例:
throw FormatException('Expected at least 1 section');
你也可以拋出任意對象:
throw 'Out of llamas!';
注意:生產質量代碼通常會拋出實現(xiàn)錯誤或異常的類型 。
因為拋出異常是一個表達式,所以可以在=>語句中以及允許表達式的任何其他地方拋出異常:
void distanceTo(Point other) => throw UnimplementedError();
Catch
要處理可能拋出多種類型異常的代碼,可以指定多個catch子句。與拋出對象的類型匹配的第一個catch子句處理異常。如果catch子句未指定類型,則該子句可以處理任何類型的拋出對象:
try {
breedMoreLlamas();
} on OutOfLlamasException {
buyMoreLlamas();
}
正如上面的代碼所示,您可以使用on或catch或兩者兼而有之。使用on時需要指定異常類型。使用catch時,你的異常處理程序需要異常對象。
要處理可能拋出多種類型異常的代碼,可以指定多個catch子句。與拋出對象的類型匹配的第一個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時需要指定異常類型。使用catch時,你的異常處理程序需要異常對象。
您可以指定一個或兩個參數(shù)catch()。第一個是拋出的異常,第二個是堆棧跟蹤(StackTrace對象)。
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
要部分處理異常,同時允許它傳播,請使用rethrow關鍵字。
void misbehave() {
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
Finally
無論是否拋出異常,要確保某些代碼運行,請使用finally子句。如果沒有catch子句匹配該異常,則在finally子句運行后傳播異常:
try {
breedMoreLlamas();
} finally {
// Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}
該finally子句在任何匹配的catch子句之后運行:
try {
breedMoreLlamas();
} catch (e) {
print('Error: $e'); // Handle the exception first.
} finally {
cleanLlamaStalls(); // Then clean up.
}
閱讀 dart之旅的Exception部分,了解更多相關信息 。