Dart基礎系列:
說明:
Dart系列的開篇(Dart簡介)總結了Dart語言的相關知識,涉及到一些基礎的概念,并介紹了如何搭建其開發環境。從這一篇開始,我將對Dart的語法進行總結,分為上下兩篇,其中本篇的內容如下:
內容:
- 關鍵字
- 數據類型
變量與常量
數據類型(內置類型) - 操作符
算數運算符;關系運算符;邏輯運算符;賦值運算符;
位和移位操作符;條件表達式;類型判定操作符;其他操作符
級聯操作符 - 控制語句
- 注釋
一、關鍵字
關鍵字 | |||
---|---|---|---|
abstract [1] | do | import [1] | super |
as [1] | var | continue | dynamic [1] |
assert [2] | else | interface | sync *[2] |
enum | is | implements [1] | export [1] |
async *[2] | this | library [1] | throw |
await | new | covariant | true |
break | null | external [1] | factory [1] |
case | try | extends | typedef [1] |
catch | false | operator [1] | switch |
class | final | finally | void |
const | part [1] | rethrow | while |
in | for | return | with |
mixin | get [1] | set [1] | yield *[2] |
default | if | static [1] | deferred [1] |
帶有[1] 的關鍵字是 內置關鍵字。避免把內置關鍵字當做標識符使用。 也不要把內置關鍵字 用作類名字和類型名字。 有些內置關鍵字是為了方便把 JavaScript 代碼移植到 Dart 而存在的。 例如,如果 JavaScript 代碼中有個變量的名字為 factory
, 在移植到 Dart 中的時候,你不必重新命名這個變量。
帶有[2] 的關鍵字,是在 Dart 1.0 發布以后又新加的,用于 支持異步相關的特性。 你不能在標記為 async*
、或者 sync*
的方法體內 使用 async
、 await
、或者 yield
作為標識符。 詳情請參考:異步支持。
所以其他單詞都是 保留詞。 你不能用保留詞作為關鍵字。
二、數據類型
1、變量與常量
- 變量聲明與初始化:
1.使用var
聲明變量,此時沒有明確類型,編譯的時候根據值明確類型
2.明確變量類型,來幫助 Dart 去捕獲異常以及 讓代碼運行的更高效
3.未初始化時,變量默認值為null
4.如果對象不限于單一類型(沒有明確的類型),請使用Object或dynamic關鍵字var name = ‘Bob’; Object name1 = '張三'; //動態類型 dynamic name2 = '李四'; // 顯示聲明將被推斷類型, 可以使用String顯示聲明字符串類型 String name3 = 'Bob' ;
- final and const
1.被final
和const
修飾的變量只能賦值一次,不可更改變量值
2.一個 final 變量只能被初始化一次; const變量是一個編譯時常量,(Const變量是隱式的final),如果 const 變量在類中,請定義為 static const。
3.被final或者const修飾的變量,變量類型可以省略,建議指定數據類型。
4.被final修飾的頂級變量或類變量在第一次聲明的時候就需要初始化,否則會提示錯誤:
5.const關鍵字不只是聲明常數變量,您也可以使用它來創建常量值,以及聲明創建常量值的構造函數,任何變量都可以有一個常量值。// The final variable 'outSideFinalName' must be initialized. final String outSideFinalName
注意:實例變量可以為 final 但是不能是 const 。// 注意: [] 創建的是一個空的list集合 // const []創建一個空的、不可變的列表(EIL)。 var varList = const []; // varList 當前是一個EIL final finalList = const []; // finalList一直是EIL const constList = const []; // constList 是一個編譯時常量的EIL // 可以更改非final,非const變量的值 // 即使它曾經具有const值 varList = ["haha"]; // 不能更改final變量或const變量的值 // 這樣寫,編譯器提示:a final variable, can only be set once // finalList = ["haha"]; // 這樣寫,編譯器提示:Constant variables can't be assigned a value // constList = ["haha"];
2、數據類型(內置類型)
2.1、num(數值)
1、int:其取值通常位于 -253 和 253 之間
2、double:64-bit (雙精度) 浮點數,符合 IEEE 754 標準。
3、數值型操作:
- 運算符:
+
、-
、*
、/
、~/
、%
其中~/
為整除 - 常用屬性:
isNaN
(是否非數字),isEven
(是否為偶數),isOdd
(是否為奇數) - 常用方法:
abs()
,round()
,floor()
,ceil()
,toInt()
,toDouble()
int a = 1; print(a); double b = 1.12; print(b); // String -> int int one = int.parse('1'); // 輸出3 print(one + 2); // String -> double var onePointOne = double.parse('1.1'); // 輸出3.1 print(onePointOne + 2); // int -> String String oneAsString = 1.toString(); // The argument type 'int' can't be assigned to the parameter type 'String' //print(oneAsString + 2); // 輸出 1 + 2 print('$oneAsString + 2'); // 輸出 1 2 print('$oneAsString 2'); // double -> String 注意括號中要有小數點位數,否則報錯 String piAsString = 3.14159.toStringAsFixed(2); // 截取兩位小數, 輸出3.14 print(piAsString); String aString = 1.12618.toStringAsFixed(2); // 檢查是否四舍五入,輸出1.13,發現會做四舍五入 print(aString);
2.2、String(字符串)
1、String的創建:
- 使用單引號''
,雙引號""
- 使用三個 引號'''
或雙引號"""
創建多行字符串
- 使用r
創建原始 raw
字符串
var s1 = '單引號字符串'; var s2 = "雙引號字符串"; var s3 = ''' 單引號多創建的多行的字符串, 第二行 '''; var s4 = """ 雙引號多創建的多行的字符串, 第二行 """; //使用r創建原始’raw‘字符串,\n不換行 var s5 = r"使用r創建原始’raw‘字符串,\n不換行";
2、字符串操作:
-
運算符:
+
,*
,==
,[]
,String a = "hello"; String b = a + " Dart!"; //hello Dart! print(b); String c = b*2; //hello Dart!hello Dart! print(c); String d = "hello Dart!"; //true print(d==b); String e = d[0]; //h print(e);
-
插值表達式:
${expression}
int e1 = 1; int e2 = 2; //a = 1 print("a = $a"); //e1 + e2 = 3 print("e1 + e2 = ${e1 + e2}");
常用屬性:
length
(長度),isEmpty
(是否為空),isNotEmpty
(是否非空)常用方法:
contains()
,subString()
,startsWith()
,endsWith()
,indexOf()
,lastIndexOf()
,toLowerCase()
,toUpperCase()
,trim()
,trimLeft()
,trimRight()
,split()
,replaceXxx()
更多API詳見官網:String class
3、StringBuffer
:
- 使用
StringBuffer
創建字符串,當調用其toString()
函數時,才會創建一個 新的String
對象。 -
write()
:將參數字符串加入StringBuffer
對象中 -
writeAll()
:此函數有一個可選的參數來指定每個字符串的分割符var sb = new StringBuffer(); //這里用到了級聯操作符 sb..write('Use a StringBuffer for ') ..writeAll(['efficient', 'string', 'creation'], ' ') ..write('.'); var fullString = sb.toString(); //Use a StringBuffer for efficient string creation. printI(fullString);
2.3、bool(布爾型)
1、使用bool表示布爾型
2、布爾值只有個true
,false
,它們都是編譯時常量。
3、Dart的類型安全意味著您不能使用 if(nonbooleanValue) 或 assert(nonbooleanValue) 等代碼, 相反Dart使用的是顯式的檢查值。
2.4、List(數組、列表)
1、List的創建:
- 創建List:
var lvs = [1, 2, 3];
- 創建不可變的List:
//其中的值不能修改 var lcs = const [1, 2, 3]; //報錯:unsupported operation: Cannot modify for an unmodifiable list lcs[0] = 5;
- 構造創建:
var lns = new List();
2、常用操作:
[]
取值,length
數組長度-
方法:
add()
添加元素,insert()
在指定位置插入,
remove()
移除元素,clear()
清空數組,
indexOf()
獲取指定元素位置,lastIndexOf()
倒序獲取指定元素位置,
sort()
排序,sublist()
截取數組,shuffle()
,
asMap()
轉換為Map,forEach()
循環遍歷,
更多API詳見官網:List<E> class//創建一個int類型的list List list = [10, 7, 23]; // 輸出[10, 7, 23] print(list); // 使用List的構造函數,也可以添加int參數,表示List固定長度,不能進行添加 刪除操作 var fruits = new List(); // 添加元素 fruits.add('apples'); // 添加多個元素 fruits.addAll(['oranges', 'bananas']); List subFruits = ['apples', 'oranges', 'banans']; // 添加多個元素 fruits.addAll(subFruits); // 輸出: [apples, oranges, bananas, apples, oranges, banans] print(fruits); // 獲取List的長度 print(fruits.length); // 獲取第一個元素 print(fruits.first); // 獲取元素最后一個元素 print(fruits.last); // 利用索引獲取元素 print(fruits[0]); // 查找某個元素的索引號 print(fruits.indexOf('apples')); // 刪除指定位置的元素,返回刪除的元素 print(fruits.removeAt(0)); // 刪除指定元素,成功返回true,失敗返回false // 如果集合里面有多個“apples”, 只會刪除集合中第一個改元素 fruits.remove('apples'); // 刪除最后一個元素,返回刪除的元素 fruits.removeLast(); // 刪除指定范圍(索引)元素,含頭不含尾 fruits.removeRange(start,end); // 刪除指定條件的元素(這里是元素長度大于6) fruits.removeWhere((item) => item.length >6); // 刪除所有的元素 fruits.clear();
-
說明:List 是泛型類型,所以可以指定里面所保存的數據類型
// This list should contain only strings. var fruits = new List<String>(); fruits.add('apples'); var fruit = fruits[0]; assert(fruit is String); // Generates static analysis warning, num is not a string. fruits.add(5); // BAD: Throws exception in checked mode.
2.5、Set(無序集合)
1、Dart 中的 Set 是一個無序集合,里面不能保護重復的數據。 由于是無序的,所以無法通過索引來從 set 中獲取數據。
2、相關方法:
add()
添加一個元素, addAll()
添加一個數組
contains()
是否包含一個元素,containsAll()
是否包含多個元素
intersection()
獲取兩個集合的交集
更多API詳見官網:Set<E> class
void main() {
var sts = new Set();
sts.add("1");
sts.addAll(['gold', 'titanium', 'xenon']);
sts.add("1"); //重復添加相同元素被覆蓋
//{1, gold, titanium, xenon}
print(sts);
//titanium
print("" + sts.elementAt(2));
//sts==>{1, gold, titanium, xenon}
print("sts==>$sts");
var sts2 = new Set.from(['xenon', 'argon']);
//sts2==>{xenon, argon}
print("sts2==>$sts2");
var sts3 = sts.intersection(sts2);
//sts3==>{xenon}
print("sts3==>$sts3");
}
注: List<E>
和Set<E>
都繼承自EfficientLengthIterable<T>
,并最終繼承Iterable<E>
類。
2.6、Map(集合)
1、說明:
· map 通常也被稱之為 字典或者 hash ,也是一個無序的集合,里面 包含一個 key-value 對。map 把 key 和 value 關聯起來可以 方便獲取數據。和 JavaScript 不同的是, Dart objects 不是 maps。
· 鍵和值都可以是任何類型的對象。
· 每個 鍵 只出現一次, 而一個值則可以出現多次。
2、創建:
//方式一:
var map1 = {
"one" : [1, "strValue", true],
"two" : "twoValue",
};
//創建不可變Map
var mapConst = const {
"one" : [1, "strValue", true],
"two" : "twoValue",
};
//方式二:未指定泛型類型
var map2 = new Map();
//方式二:指定泛型類型
var map3 = new Map<int, String>();
3、常用屬性/方法:
length
Map長度, keys
返回所有key值,values
返回所有的value值
isEmpty()
是否為空Map, isNotEmpty()
是否為非空Map
[]
新增一個元素,remove()
移除一個元素,并將元素返回
containsKey()
是否包含一個key
putIfAbsent(key, function)
設置 key 的值,但是只有該 key 在 map 中不存在的時候才設置這個值,否則 key 的值保持不變。該函數需要 一個方法返回 value
。
forEach()
遍歷Map
var map1 = {
"one" : [1, "strValue", true],
"two" : "twoValue",
};
//null
print(map1["x"]);
//[1, strValue, true]
print(map1["one"]);
//true
print(map1.containsKey("one"));
var result = map1.remove("two");
//result==>twoValue,,map1==>{one: [1, strValue, true]}
print("result==>$result,,map1==>$map1");
//提示:the argument type 'int' can't be assigned to be parameter type 'String'
//map1[1] = 123;
var map11 = {
"one" : [1, "strValue", true],
"two" : "twoValue",
2 : new List()
};
//不會提示錯誤
map11[1] = 123;
//新增一個元素
map1["three"] = "addValue";
var keys = map1.keys;
//keys==>(one, three)
print("keys==>$keys");
var values = map1.values;
//values==>([1, strValue, true], addValue)
print("values==>$values");
map1.putIfAbsent("four", ()=> 1+2);
map1.putIfAbsent("four", ()=> "返回一個value");
//map1==>{one: [1, strValue, true], three: addValue, four: 3}
print("map1==>$map1");
print("==========================");
/*
one==>[1, strValue, true]
three==>addValue
four==>3
*/
map1.forEach((key, value)=> {
print("$key==>$value")
});
print("==========================");
/*
one==[1, strValue, true]
three==addValue
four==3
*/
for(var me in map1.entries) {
print("${me.key}==${me.value}");
}
說明:
1、從上面的代碼可以看出,在map中,如果初始的key值都是同一類型,則在通過[]
方式添加的時候,只能添加相同類型的值作為key。
2、雖然 Map 沒有實現 Iterable,但是 Map 的 keys 和 values 屬性實現了 Iterable。
Iterable<K> get keys;
Iterable<V> get values;
3、和Java一樣,在Map中也有一個內部類MapEntry<K, V>
,可以通過其屬性entries獲取到MapEntry<K, V>
類型的迭代器Iterable
,以此來進行遍歷。
2.7、dynamic(動態類型)
1、注意:
dynamic并非Dart中的內置類型,
沒有指定類型的變量的類型為 dynamic
,
dynamic
一般在使用泛型時使用
2、示例:
dynamic a = 10;
//a==>10
print("a==>$a");
a = "六六六";
//a==>六六六
print("a==>$a");
var ls = new List<dynamic>(); //泛型,會在后面總結
ls.add("哈哈");
ls.add(333);
//ls==>[哈哈, 333]
print("ls==>$ls");
2.8、runes(符號文字)[不常用]
-
簡介:
在 Dart 中,runes 代表字符串的 UTF-32 code points。Unicode 為每一個字符、標點符號、表情符號等都定義了 一個唯一的數值。 由于 Dart 字符串是 UTF-16 code units 字符序列, 所以在字符串中表達 32-bit Unicode 值就需要 新的語法了。
可以實現一些表情的符號文字。
-
Unicode code point的表示方式:
\uXXXX
這里的 XXXX 是4個 16 進制的數。
-
示例:
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)); } //打印結果:=============================== ?? [55357, 56399] [128079] ? ?? ?? ?? ?? ??
2.9、Symbols(標志)[不常用]
-
簡介:
一個 Symbol object 代表 Dart 程序中聲明的操作符或者標識符。此標識符常用于對于通過名字來引用標識符的情況,特別是混淆后的代碼, 標識符的名字被混淆了,但是 Symbol 的名字不會改變。
Symbol 字面量定義的是編譯時常量。
-
使用:
使用 Symbol 字面量來獲取標識符的 symbol 對象,也就是在標識符 前面添加一個 # 符號:#radix #bar
關于 symbols 的詳情,請參考 dart:mirrors - reflection。
三、操作符
1、算數運算符:
-
+
加、-
減、*
乘、/
除、~/
取整、%
取模(余)、-expr
負數 -
++expr
先遞增、expr++
后遞增、--expr
先遞減、expr--
后遞減
2、關系運算符:
-
==
相等、!=
不等、>=
大于等于、>
大于、<=
小于等于、<
小于
3、邏輯運算符:
-
!
取反、&&
并且、||
或者
4、賦值運算符:
-
=
等于、+=
加等于、-=
減等于、
*=
乘等于、/=
除等于、
%=
取模(余)等于、~/=
取整等于
<<=
左移等于、>>=
右移等于
^=
非等于、&=
且等于、|=
或等于
??=
判空等于:如果??=
左邊的變量為無值,則將右邊的值賦值給變量,否則不賦值int a = 10; int b; a ??= 20; b ??=5; //a = 10 a有值10,所以不會賦值20 print("a = $a"); //b = 5 b無值,則將5賦值給b print("b = $b");
5、位和移位操作符
&
且、|
或、^
非、<<
左移、>>
右移
5、條件表達式
condition ? expr1 : expr2
三目運算符
expr1 ?? expr2
返回其中不為空的表達式執行結果
String a = "Hello";
String b = "";
String c = "Dart";
String d = a ?? b;
String e = b ?? c;
//d = Hello
print("d = $d");
//e = Dart
print("e = $e");
6、類型判定操作符
as
、is
、和 is!
操作符是在運行時判定對象
as
:類型轉換
is
:如果對象是指定的類型返回 True
is!
:如果對象是指定的類型返回 False
具體例子參考面向對象的總結
7、其他操作符
-
()
:使用方法。代表調用一個方法 -
[]
:訪問 List。訪問 list 中特定位置的元素
.
:訪問 Member(成員)。訪問元素,例如 foo.bar 代表訪問 foo 的 bar 成員
?.
:條件成員訪問。和.
類似,但是左邊的操作對象不能為 null,例如foo?.bar
如果foo
為null
則返回null
,否則返回bar
成員
8、級聯操作符
..
:級聯操作符 (..) 可以在同一個對象上 連續調用多個函數以及訪問成員變量。使用級聯操作符可以避免創建臨時變量,并且寫出來的代碼看起來更加流暢。(具體詳見面向對象中的例子)
querySelector('#button') // Get an object.
..text = 'Confirm' // Use its members.
..classes.add('important')
..onClick.listen((e) => window.alert('Confirmed!'));
說明:
第一個方法 querySelector()
返回了一個 selector
對象。后面的級聯操作符都是調用這個對象的成員,并忽略每個操作所返回的值。
四、控制語句
- if...else,if...else if,if...else if...else
int score = 95; if (score > 90) { print("優秀"); } else if (score > 60) { print("及格"); } else { print("完蛋玩意兒"); } //優秀
- for,for...in
var list = [1, 2, 3, 4, 5]; for (var item in list) { print(item); }
- while do-while
int count = 5; while(count > 0) { print("index => $count"); count--; } int length = 5; do { print("index ==> $length"); length--; } while(length > 0);
- break continue
List ls = [1, 2, 3, 4, 5, 6, 7, 8, 9]; for (var i = 1; i<=ls.length; i++) { if (i%4==0) { break; } if (i%3==0) { continue; } print("index ==> ${ls[i]}"); } //index ==> 2 //index ==> 3
- switch...case
其中可以使用跳轉標簽(自定義標簽名稱)
打印結果為:Stirng lang = “Dart"; switch (lang) { D: case "Dart": print("This is Dart!"); break; case "Java": print("This is Java!"); break; case "Flutter": print("This is Flutter!"); continue D; //break; //不需要了 default: print("This is NONE!"); break; }
This is Flutter! This is Dart!
- assert (斷言)
1、如果條件表達式結果不滿足需要,則可以使用 assert 語句倆打斷代碼的執行。
2、斷言只在檢查模式下運行有效,如果在生產模式 運行,則斷言不會執行。
3、assert
方法的參數可以為任何返回布爾值的表達式或者方法。
如果返回的值為 true, 斷言執行通過,執行結束。 如果返回值為 false, 斷言執行失敗,會拋出一個異常 AssertionError// 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'));
四、注釋
Dart 支持單行注釋、多行注釋和 文檔注釋。
-
單行注釋:
單行注釋以//
開始。//
后面的一行內容 為 Dart 代碼注釋。main() { // TODO: refactor into an AbstractLlamaGreetingFactory? print('Welcome to my Llama farm!'); }
-
多行注釋:
多行注釋以/*
開始,*/
結尾。 多行注釋可以嵌套。main() { /* * This is a lot of work. Consider raising chickens. Llama larry = new Llama(); larry.feed(); larry.exercise(); larry.clean(); */ }
-
文檔注釋:
文檔注釋可以使用///
開始, 也可以使用/**
開始 并以*/
結束。在文檔注釋內, Dart 編譯器忽略除了中括號以外的內容。 使用中括號可以引用
classes
、methods
、fields
、top-level variables
、functions
、 和parameters
。中括號里面的名字使用 當前注釋出現地方的語法范圍查找對應的成員。/// A domesticated South American camelid (Lama glama). /// /// Andean cultures have used llamas as meat and pack /// animals since pre-Hispanic times. class Llama { String name; /// Feeds your llama [Food]. /// /// The typical llama eats one bale of hay per week. void feed(Food food) { // ... } /// Exercises your llama with an [activity] for /// [timeLimit] minutes. void exercise(Activity activity, int timeLimit) { // ... } }
使用 SDK 中的 文檔生成工具可以解析文檔并生成 HTML 網頁。 關于生成的文檔示例,請參考 Dart API 文檔。 關于如何 組織文檔的建議,請參考 Dart 文檔注釋指南。