一、運算符
Dart 中,支持各種類型運算符,且其中的一些操作符還支持重載操作。
1. 算數(shù)運算符
Dart 中的算數(shù)運算符有以下幾種:+
、-
、*
、/
、%
、~/
,通過以下示例說明:
main(){
var a = 21;
var b = 10;
var c;
c = a + b; //加法操作
print(c); //輸出 31
c = a - b; //減法操作
print(c); //輸出 11
c = a * b; //乘法操作
print(c); //輸出 210
c = a / b; //除法操作,兩個相除結(jié)果為double,即便兩個整數(shù)相除也為double
print(c); //輸出 2.1
c = a % b; //取余操作
print(c); //輸出 1
c = a ~/ b; //取整操作
print(c); //輸出 2
print(-c); //負(fù)數(shù)操作,輸出 -2
}
Dart 支持自增與自減操作,如下:
main(){
var a, b, c;
a = 21;
b = 10;
c = a++ + b; //a參與運算完畢后自增加1
print(c); //輸出 31
a = 21;
b = 10;
c = ++a + b; //a自增加1后參與運算
print(c); //輸出 32
a = 21;
b = 10;
c = a-- + b; //a參與運算完畢后自減1
print(c); //輸出 31
a = 21;
b = 10;
c = --a + b; //a自減1后參與運算
print(c); //輸出 20
}
另外 +
運算符也可用于字符串連接。
2. 比較運算符
比較運算符有:==
、!=
、>
、<
、>=
、<=
。使用例子如下:
main(){
var a = 20;
var b = 30;
if(a == b) {
print("a等于b");
}else if(a != b){
print("a不等于b"); //輸出 a不等于b
}
if(a > b) {
print("a大于b");
}else if(a < b) {
print("a小于b"); //輸出 a小于b
}
if(a >= b) {
print("a大于等于b");
}else if(a <= b) {
print("a小于等于b"); //輸出 a小于等于b
}
}
3. 類型運算符
Dart 中類型運算符有三種:is
、as
、is!
,用于運行時檢查類型。
is
運算符用來判斷數(shù)據(jù)是否屬于某個類型,屬于返回 true
,不屬于返回 false
。如果ojb
實現(xiàn)了 T
定義的接口,則 obj is T
為 true
。
is!
運算符用來判斷數(shù)據(jù)是否不屬于某個類型,不屬于返回 true
, 屬于返回 false
。
as
運算符用來做類型轉(zhuǎn)換,此轉(zhuǎn)換并非真正的轉(zhuǎn)換,而是把原對象當(dāng)做目標(biāo)對象使用,不會改變原對象。當(dāng)使用 as
運算符時,應(yīng)先確定原對象是否屬于目標(biāo)類型,如果不是目標(biāo)類型的子類或?qū)嵗荒苁褂?as
運算符。as
也可用于做指定庫的前綴操作(后續(xù)會講到)。
main(){
var str = "this is a string!";
if(str is String) {
print("str 是字符串");
}else{
print("str 不是字符串");
}
var a = 10;
if(a is! String) {
print("a 不是字符串");
}else{
print("a 是字符串");
}
var b =(a as num) + 10; //如不確定a是否為num的實例或子類,可以使用is操作符做先行判斷。如無法轉(zhuǎn)換會拋出異常
print(b);
}
4. 邏輯運算符
邏輯運算符是針對布爾值進(jìn)行運算的運算符,包括:!
、||
、&&
。
!
邏輯非運算符,其只有一個操作數(shù)。當(dāng)操作數(shù)布爾值為 true
時,運算結(jié)果為 false
,運算數(shù)布爾值為 false
,運算結(jié)果為 true
。
||
邏輯或運算符,有兩個操作數(shù)。當(dāng)操作數(shù)中至少有一個為 true
時,結(jié)果為 true
,操作數(shù)都為 false
,結(jié)果為 false
。
&&
邏輯與運算符,有兩個操作數(shù)。當(dāng)操作數(shù)中至少有一個為 false
時,結(jié)果為 false
,操作數(shù)都為 true
,結(jié)果為 true
。
||
和 &&
均為短路運算符。
main(){
print(!true); //輸出 flase
print(!false); //輸出 true
print(true || false); //輸出 true
print(false || true); //輸出 true
print(true || true); //輸出 true
print(false || false);//輸出 false
print(true && false); //輸出 false
print(false && true); //輸出 false
print(true && true); //輸出 true
print(false && false);//輸出 false
}
5. 條件運算符
條件運算符包括:?:
、??
或 ??=
。
main(){
var a = 10;
var b = 20;
var c = a>b ? a : b; //如果a大于b則返回a的值賦給c,否則返回b的值賦給c
print(c);
//?? 與 ??= 一樣,為空運算符
print(a ?? 100); //輸出 10 如果a為null則將100賦值給a,如果a不為null則使用a的值
var d;
print(d ??= 200); //輸出200
}
6. 位運算符
位運算符是針對二進(jìn)制位進(jìn)行操作的運算符。包括:&
、|
、^
、~
、<<
、>>
。
&
按位與運算符,是將兩個操作數(shù)的每一個二進(jìn)制位分別做與運算,對應(yīng)的兩個二進(jìn)制位都為1則結(jié)果為1,否則為0。
|
按位或運算符,是將兩個操作數(shù)的每一個二進(jìn)制位分別做或運算,對應(yīng)的兩個二進(jìn)制位至少有一個為1則結(jié)果為1,否則為0。
^
按位異或運算符,是將兩個操作數(shù)的每一個二進(jìn)制位分別做異或運算,對應(yīng)的兩個二進(jìn)制位相同(同為1或同為0)則結(jié)果為0,否則為1。
~
按位取反運算符,只有一個操作數(shù),是將操作數(shù)的每一個二進(jìn)制位進(jìn)行取反操作,即1取反為0,0取反為1。
<<
按位左移運算符,是將操作數(shù)的每一個二進(jìn)制位向左移動指定的位數(shù)。每左移一位相當(dāng)于原數(shù)值乘2。
>>
按位右移運算符,是將操作數(shù)的每一個二進(jìn)制位向右移動指定的位數(shù)。每右移一位相當(dāng)于原數(shù)值除以2。
main(){
int a = 10; //二進(jìn)制為00001010
int b = 5; //二進(jìn)制為00000101
print(a & b); //運算后二進(jìn)制為0000 0000,輸出結(jié)果為 0
print(a | b); //運算后二進(jìn)制為0000 1111,輸出結(jié)果為 15
print(a ^ b); //運算后二進(jìn)制為0000 1111,輸出結(jié)果為 15
print(~a); //運算后二進(jìn)制為1111 0101,輸出結(jié)果為 -11 可以通過-(a+1)公式快速得出結(jié)果。
print(a << 2); //運算后二進(jìn)制為0010 1000,輸出結(jié)果為 40
print(b >> 2); //運算后二進(jìn)制為0000 0001,輸出結(jié)果為 1
}
7. 復(fù)合運算符
復(fù)合運算符是多種簡單運算的復(fù)合,包括:+=
、-=
、*=
、/=
、~/=
、%=
、<<=
、>>=
、&=
、^=
、|=
。
main(){
double a = 10.0; //二進(jìn)制為00001010
int b = 20; //二進(jìn)制為00000101
print(a += 10); //輸出(此時的a值) 20,0
print(a -= 10); //輸出(此時的a值) 10,0
print(a *= 10); //輸出(此時的a值) 100,0
print(a /= 10); //輸出(此時的a值) 10,0
print(b ~/= 10); //輸出(此時的b值) 2
print(b %= 10); //輸出(此時的b值) 2
print(b <<= 2); //輸出(此時的b值) 8
print(b >>= 2); //輸出(此時的b值) 2
print(b &= 5); //輸出(此時的b值) 0
print(b ^= 5); //輸出(此時的b值) 5
print(b |= 5); //輸出(此時的b值) 5
}
8. 級聯(lián)運算符
級聯(lián)運算符是 Dart 中比較高級的運算符,用于對同一對象執(zhí)行一系列操作,使用 ..
表示。使用級聯(lián)運算符可以減少中間變量的生成,如下:
main(){
List lst = List()
..add(1)
..add(2)
..addAll([3, 4, 5]);
print(lst);
}
級聯(lián)運算符也可以嵌套使用。
9. 點運算符
點運算符用來對對象的屬性和方法進(jìn)行操作。使用點運算符操作對象中不存在的屬性或方法時會拋出異常,同樣也不能操作 null
對象,如果不確定對象是否為空,則可使用條件訪問運算符 ?.
。如果需要操作的對象為空會返回 null
,否則正常操作。
main(){
var lst = [1, 2, 3];
print(lst.length); //輸出 3
lst = null;
// print(lst.length); //運行此行會拋出異常
print(lst?.length); //輸出 null
}
二、流程控制
流程控制語句與其他語言沒有什么區(qū)別,下面簡單的只列出代碼,不做過多講解。需要注意在 Dart 中條件的真假只有 true
和 false
,或它能得出 true
和 false
的表達(dá)式。
1. if 和 else
main(){
int score = 80;
if(score >= 100) {
print("滿分");
}else if(score >= 60) {
print("及格");
}else{
print("不及格");
2. for 、while 、do while
main(){
List arr = [1, 2, 3, 4, 5];
//第一種for
for(int i = 0; i < arr.length; i++) {
print(arr[I]);
}
print("-----分割線-----");
//第二種for
for(var x in arr) {
print(x);
}
print("-----分割線-----");
int i = 0;
while(i < 5) {
print(arr[I]);
I++;
}
print("-----分割線-----");
i = 0;
do{
print(arr[I]);
I++;
}while(i < 5);
}
3. break 和 continue
break
用于跳出與 break
最近的循環(huán),continue
用于跳出本次執(zhí)行的循環(huán)。
main(){
List arr = [[1, 2], [3, 4, 5], [7, 8, 9]];
//正常的循環(huán),輸出1,2,3,4,5,6,7,8,9
for(int i = 0; i < arr.length; i++) {
for(int j = 0; j < arr[i].length; j++) {
print(arr[i][j]);
}
}
//break,當(dāng)j == 1時跳出里層for循環(huán),所以最終只打印了數(shù)組的1,3,7
for(int i = 0; i < arr.length; i++) {
for(int j = 0; j < arr[i].length; j++) {
if(j == 1) {
break;
}
print(arr[i][j]);
}
}
//continue 當(dāng)j==1時,跳出單次循環(huán),繼續(xù)下次循環(huán) 輸出 1,3,5,7,9
for(int i = 0; i < arr.length; i++) {
for(int j = 0; j < arr[i].length; j++) {
if(j == 1) {
continue;
}
print(arr[i][j]);
}
}
}
4. switch 和 case
Dart 中 switch
參數(shù)可以使用整型、字符串或編譯時常量,case
后對象必須全部是同一類的實例。通常,每個非空 case
子句都以 break
結(jié)尾。結(jié)束非空 case
子句的其他有效方法為 continue
、throw
、return
。
main(){
String single = "e";
switch(single) {
case "h":
print("h");
break;
case "e":
print("e");
break;
case "l":
print("l");
break;
case "o":
print("o");
break;
default:
print("error");
break;
}
}
可以使用 continue
來進(jìn)行跳轉(zhuǎn)執(zhí)行,如下:
main(){
String single = "e";
switch(single) {
case "h":
print("h");
break;
case "e":
print("e"); //輸出 e
continue jumpOther;
case "l":
print("l");
break;
jumpOther:
case "o":
print("o"); //輸出 o
break;
default:
print("error");
break;
}
}
上述代碼在 case "o":
上添加了一個 jumpOther
標(biāo)簽,并在 case "e":
處通過 continue jumpOther
進(jìn)行了調(diào)用,輸出e后繼續(xù)執(zhí)行o。
三、異常處理
異常是一種錯誤,在程序的運行過程中造成異常的情況有很多,如果不加以識別和控制將引發(fā)程序被掛起,造成程序崩潰而結(jié)束程序。Dart 中的異常都是未經(jīng)檢查的異常。Dart 中提供了 Exception
和 Error
類型,以及許多預(yù)定義的子類型,也可以自定義異常。Dart 程序可以拋出任何非 null
對象,而非僅限于 Exception
和 Error
。
拋出異常
main(){
throw FormatException("這是一個FormatException");
// print("程序結(jié)束"); //此處不會被執(zhí)行
}
//拋出的異常 Unhandled exception: FormatException: 這是一個FormatException
main(){
throw 400; //拋出自定義的任意非null異常
// print("程序結(jié)束"); //此處不會被執(zhí)行
}
//拋出的異常 Unhandled exception: 400
捕獲異常
捕獲異常的目的在于組織異常的傳播,并進(jìn)行一定的處理措施??梢詫⒂锌赡馨l(fā)生異常的代碼放在 try
代碼塊中并使用 catch
捕獲。如果需要捕獲的異常不止一種,可以使用多個 catch
?;拘问饺缦拢?/p>
main(){
try{
throw "拋出一個字符串提示異常";
}on RangeError catch(e) {
// print(e);
}on String catch(e) {
print("字符串異常");
}catch(e, s) { //e為異常信息,s為異常的棧跟蹤信息
print("其他異常:$e");
print("棧信息:$s");
}
}
上面代碼主動拋出一個異常,是一句字符串的提示信息,所以下面將執(zhí)行 print("字符串異常")
,on
后接一個異常的具體類型,因為我們拋出的是字符串異常信息,所以會進(jìn)入 on String catch(e)
,當(dāng)然可以定義其他具體異常類型。如果捕獲的異常并非 on
后接的異常類型,則進(jìn)入最后的未定義具體類型的異常。catch
方法可以有一個參數(shù)參數(shù)或兩個參數(shù),一個參數(shù)時,參數(shù)為異常提示信息,兩個參數(shù)時,第一個參數(shù)為異常提示信息,第二個為異常的堆棧信息(StackTrace
對象)。
main(){
List arr = [1, 2, 3];
try{
print(arr[3]);
}on int catch(e) {
print(e);
}on String catch(e) {
print("字符異常");
}catch(e, s) { //e為異常信息,s為異常的棧跟蹤信息
print("其他異常:$e");
print("棧信息:$s");
}
}
異常異常類型為 RangeError
類型,所以通過 on
捕獲的 int
和 String
類型都不對,進(jìn)入最后的 catch
。
即使捕獲到了異常,開發(fā)者也可以根據(jù)具體情況決定是處理、忽略還是繼續(xù)拋出異常,如果需要繼續(xù)拋出,可使用 rethrow
關(guān)鍵字。 rethrow
允許部分處理異常或直接繼續(xù)拋出異常給其他方法處理。
main(){
List arr = [1, 2, 3];
try{
try{
print(arr[3]);
}catch(e){
rethrow;
}
}on int catch(e) {
print(e);
}on String catch(e) {
print("1");
}catch(e, s) { //e為異常信息,s為異常的棧跟蹤信息
print("其他異常:$e");
print("棧信息:$s");
}finally {
print("善后處理或拋出異常后需要繼續(xù)執(zhí)行的代碼");
}
}
此外有時需要無論是否拋出異常都執(zhí)行指定的代碼,則需要使用到 finally
關(guān)鍵字,如下:
main(){
List arr = [1, 2, 3];
try{
print(arr[3]);
}on int catch(e) {
print(e);
}on String catch(e) {
print("字符異常");
}
catch(e, s) { //e為異常信息,s為異常的棧跟蹤信息
print("其他異常:$e");
print("棧信息:$s");
}finally {
print("善后處理或拋出異常后需要繼續(xù)執(zhí)行的代碼");
}
}
四、斷言
Dart 中使用 assert
來調(diào)試程序的執(zhí)行,使用 assert
如果布爾條件為假,則中斷正常執(zhí)行,并拋出異常。assert
中的條件是任何可以轉(zhuǎn)化為布爾類型的對象,即使函數(shù)也可以。
main(){
print("執(zhí)行第一步"); //輸出 執(zhí)行第一步
assert(1 == 1); //條件為真,繼續(xù)執(zhí)行
print("執(zhí)行第二步"); //輸出 執(zhí)行第二步
assert(1 == 2); //條件為假,拋出異常
print("執(zhí)行第三步"); //不執(zhí)行此處
}
//以上會拋出如下異常:
//執(zhí)行第一步
//執(zhí)行第二步
//Unhandled exception:
//Failed assertion: line 5 pos 10: '1 == 2': is not true.
//#0 _AssertionError._doThrowNew (dart:core-patch/errors_patch.dart:42:39)
//#1 _AssertionError._throwNew (dart:core-patch/errors_patch.dart:38:5)
//#2 main
//Dart/demo1.dart:5
//#3 _startIsolate.<anonymous closure> (dart:isolate-patch/isolate_patch.dart:307:19)
//#4 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
//Exited (255)
可以附加自己的說明在 assert
里,如下:
main(){
assert(1 == 2, "這里的條件不成立,1不等2");
print("不會執(zhí)行");
}
assert
可以有兩個參數(shù),第一個為任意可以解析為布爾值的表達(dá)式,第二個為附加說明信息。
在生產(chǎn)代碼中,assert
將被忽略,并且不會評估斷言的參數(shù)。
PS:如果您使用的是 VSCode 來運行 以上斷言代碼,如果安裝有 Code Runner 插件并使用此插件來運行代碼,則斷言不會執(zhí)行,需要通過 Debug -> Start Debugging 或 Debug -> Start Without Debugging 來運行代碼才會執(zhí)行斷言代碼。