Dart語言特性必備瞭解!
學習Dart語言,必須將以下的概念熟記於心:
- 在dart語言中,一切皆為物件。所有的物件都是一個類的例項。甚至整數、函式、null也看做是物件。所有的物件都繼承於Object類
- 儘管Dart是強型別語言,但是變數的型別指定不一定要標明,因為Dart可以推斷出它的型別。比如說變數number就可以被推測出是int型別。如果你想明確表示這個變數不想被任何一個型別指定,那就使用特殊型別dynamic來表示。
- Dart語言支援通用型別,比如List<int>表示整數集列表,List<dynamic>表示元素集為任意型別物件的列表
- Dart支援頂級函式(如main()),以及繫結到類或物件的函式(分別是靜態方法和例項方法)。您還可以在函式中建立函式(巢狀函式或本地函式)。
- 類似的,Dart支援頂級變數,以及繫結到類或物件(靜態和例項變數)的變數。例項變數有時稱為欄位或屬性。
- 有別於JAVA語言,dart語言中沒有public、protected和private這些關鍵字。在dart裡面,如果識別符號以下劃線(_)開頭,那麼它對其庫是私有的
-
Dart裡面的標誌符號由
_
、字母和數字組成,只能以_
或者字母開頭 - Dart既有表示式(具有執行時值),也有語句(不具有執行時值)。比如傳統的表示式condition ? expr1 : expr2會有一個值,expr1或者expr2。相比較於if-else語句,則沒有值。一個語句通常包括一個或者多個表示式,但是一個表示式不能直接包含一個語句。
- Dart工具會向你發出兩種型別問題:警告和錯誤。警告則是指出你的程式碼存在問題,但是不會阻止你正在執行的程式。錯誤則會發生在編譯時和執行時。編譯時的錯誤會完全阻止你程式碼的執行。執行時錯誤導致程式碼執行時引發異常。
變數
定義一個變數name並初始化一個String型別的值zeng:
var name = 'zeng'
這個name變數的型別會自動推斷出String型別,但是你也可以通過其他方法來改變型別。如果你不想讓一個變數僅僅受限為一個型別,你可以指定這個變數是Object或者dynamic型別,如下面的做法:
dynamic name = 'zeng'
還有一個做法就是顯示的宣告你即將定義的變數的型別,如:
String name = 'zeng'
如果你定義了一個變數而沒有初始化值,則這個變數有一個預設值null。即使變數是個數值型別(int),也是null,因為在dart語言中,一切皆為物件。
int a; assert(a == null)
final 和 const
如果你不想改變一個變數,使用final和const是最好的選擇。final變數只能設定一次 ,const變數是一個編譯時常量。頂層final或者class變數在第一次使用時就初始化 了。
定義一個final變數:
final name = 'zeng';//沒有一個型別宣告 final String nickName = 'lucky';
上面定義的final變數如果你改變他的值,則會報錯:
name = 'fan';//Error: a final variable can only be set once.
用const來定義一個編譯時的變數。如果const變數位於class級別,則將其標記為靜態const。在宣告變數的地方,將值設定為編譯時常量,如數字或字串文字、常量變數或對常量進行算術運算的結果:
const a = 1000; const double b= 1.05 * a;
資料型別
Dart語言有以下七種內建資料型別
- numbers
- strings
- booleans
- lists (also known as arrays )
- maps
- runes (for expressing Unicode characters in a string)
- symbols
Numbers
Dart有兩種數值型別
int整數型
整數型的值不超過64位,取決於平臺。如果在Dart VM平臺,整數值的取值範圍是 -263 ~ 263 - 1。dart如果是編譯為javascript語言中javascript numbers,則取值為-253 ~ 253 - 1。
doubel浮點型
int和double型別都是數值型的子型別,這數值型別包括一些基本的運算子操作如 + 、- 、/ 和*,當然還有一些其他方法 abs()、ceil()、floor()。
int就是沒有小數點的數值。比如:
var x = 1; var y = 0xDEADBEEF;
而如果是有小數點的數值,它就是一個浮點型,比如:
var y = 1.1; var exponents = 1.42e5;
在Dart2.1版本中,在必要的時候,整數型的數值會自動轉換成浮點型的數值。比如
double z = 1; // Equivalent to double z = 1.0.
下面的是演示怎樣讓字元型轉換成數值型,反之亦然:
// 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型別也可進行按位操作(<<,>>)(&)、(|)
assert((3 << 1) == 6); // 0011 << 1 == 0110 assert((3 >> 1) == 1); // 0011 >> 1 == 0001 assert((3 | 4) == 7); // 0011 | 0100 == 0111
數字字面量是編譯時的常量。許多算術運算表示式也是編譯時的常量,只要他們的運算元是編譯時常量,計算結果是數字就行。比如:
const a = 100; const b = 10; const c = a * b;
String字串
Dart字串是一系列UTF-16程式碼單元組成。你可以用單引號或者雙引號括起來組成一個字串。
var s1 = 'use single quotes.'; var s2 = "use double quotes.";
通過${expression} 這個方法可以把表示式的值放入一個string中,如果這個表示式是個識別符號,你也可以省略這個{}
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!');
下面是連線字串的方法:
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.');
如果你要寫多行的字串,你可以使用三個單引號或者三個雙引號來標記:
var s1 = ''' You can create multi-line strings like this one. '''; var s2 = """This is also a multi-line string.""";
可以通過r方法,讓你的字串程式碼原樣輸出:
var s = r'this is a test \n ,tell me';
Booleans布林型別
Dart使用bool型別來表示布林值。ture 和false是bool的兩個物件,同時這兩個也是編譯時常量
在dart語言中,我們不能使用javascript中的判斷語句,比如:
var a = ''; //在javascript中 if(a){ console.log('nice') } //但是在dart語言中,不能這樣進行判斷。而要使用下面的方法 if(a.isEmpty) //檢查是否為null var b ; assert(b == null) //檢查是否為NaN var c = 0/0; assert(c.isNaN)
Lists列表型
陣列(array)幾乎是所有程式語言中最常見的集合。但在Dart語言中,陣列就是List物件。
dart中的list就像是javascript中的Array。通過下面的例子瞭解dart中的list
var list = [1, 2, 3]; assert(list.length == 3); assert(list[1] == 2); list[1] = 1; assert(list[1] == 1);
Lists也有length,list中資料的表示方法也和陣列一樣可以通過索引號碼來訪問特定的元素,比如List[1]。
Maps
通常來說,map是鍵值對型別的物件。key和value可以是任意型別的物件。但是不能出現相同的key,每個key只能出現一次,而相同的值可以多次出現。
var gifts = { // Key:Value 'first': 'partridge', 'second': 'turtledoves', 'fifth': 'golden rings' }; //新增一個key-value對 gifts['fourth'] = 'nice baby'; var nobleGases = { 2: 'helium', 10: 'neon', 18: 'argon', };
如上,key值中有了first,就不能再出現key為first的一項,不然會報錯。除了通過上面的字面量方法來建立map,也可以通過map構造器來建立物件
var gifts = Map(); gifts['first'] = 'partridge'; gifts['second'] = 'turtledoves'; gifts['fifth'] = 'golden rings'; var nobleGases = Map(); nobleGases[2] = 'helium'; nobleGases[10] = 'neon'; nobleGases[18] = 'argon';
如果你查詢map物件裡面不存在的key,則會返回一個null
var gifts = {'first': 'partridge'}; assert(gifts['fifth'] == null);
可以通過.length的方法獲取map中的鍵值對數量:
var gifts = {'first': 'partridge'}; gifts['fourth'] = 'calling birds'; assert(gifts.length == 2);
Functions函式集
bool isNoble(int atomicNumber) { return _nobleGases[atomicNumber] != null; }
宣告函式型別可以提升函式執行效率,如果省略這些型別,也是可以執行的:
isNoble(atomicNumber) { return _nobleGases[atomicNumber] != null; }
如果只有一個表示式,你可以簡寫為:
bool isNoble(int atomicNumber) => _nobleGases[atomicNumber] != null;
函式可選引數
當呼叫一個函式,你需要指明引數paramName: value,比如:
enableFlags(bold: true, hidden: false);
當定義一個函式,你可以使用{param1,param2,....}來命名引數:
void enableFlags({bool bold, bool hidden}) {...}
如果是一個必須傳入的引數,則需要使用@required來指明引數:
const Scrollbar({Key key, @required Widget child})
我們也可以在[]中放置一個可選的引數:
String say(String from, String msg, [String device]) { var result = '$from says $msg'; if (device != null) { result = '$result with a $device'; } return result; }
在上面的[]中的引數,可傳也可以不傳。如果我們想給一個引數一個預設的值,就可以使用如下的方法:
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');
當呼叫say函式時,沒有傳入device引數和mood引數,但是device引數有一個預設值‘carrrer pigeon’,所以不傳這個引數,則會預設把預設值放入到函式中執行。
main()函式
每個app都必須有main()函式,main()函式是作為app的入口函式。一個web app的入口函式如下:
void main() { querySelector('#sample_text_id') ..text = 'Click me!' ..onClick.listen(reverseText); }
注:..
是一種級聯操作符,它返回呼叫者本身,這樣就可以連續呼叫同一個物件上的多個方法,實現鏈式操作!
函式可以作為另一個函式的引數執行,如
void printElement(int element) { print(element); } var list = [1, 2, 3]; // Pass printElement as a parameter. list.forEach(printElement);
型別檢查操作符
as、 is、 is!
比如:
if (emp is Person) { // Type check emp.firstName = 'Bob'; }
分配符
// Assign value to a a = value; // Assign value to b if b is null; otherwise, b stays the same b ??= value;