Flutter開發之Dart語法基礎

RunTitan發表於2019-02-19

dart-logo

  • 原文部落格地址: Flutter開發之Dart語法基礎
  • Dart是谷歌在 2011 年推出的程式語言,是一種結構化Web程式語言,允許使用者通過Chromium中所整合的虛擬機器(Dart VM)直接執行Dart 語言編寫的程式,免去了單獨編譯的步驟
  • 以後這些程式將從Dart VM更快的效能與較低的啟動延遲中受益
  • Dart從設計之初就為配合現代web整體運作而考慮,開發團隊也同時在持續改進DartJavaScript轉換的快速編譯器
  • Dart VM以及現代JavaScript引擎(V8 等)都是Dart語言的首選目標平臺
  • Dart語言和Swift語言有很多的相似之處

重要概念

在學習Dart語言之前, 先了解一些Dart相關的一些概念:

  • O-Objective中有一切皆物件的說法, 這句話在Dart中同樣適用
    • 所有能夠使用變數引用的都是物件, 每個物件都是一個類的例項
    • Dart中 甚至連 數字、方法和null都是物件
    • 所有的物件都繼承於Object
  • Dart動態型別語言, 儘量給變數定義一個型別,會更安全,沒有顯示定義型別的變數在debug模式下會型別會是dynamic(動態的)
  • Dart會在執行之前解析你的所有程式碼,指定資料型別和編譯時的常量,可以提高執行速度
  • Dart中的類和介面是統一的,類即介面,你可以繼承一個類,也可以實現一個類(介面),自然也包含了良好的物件導向和併發程式設計的支援
  • Dart函式
    • 支援頂級函式 (例如main())
    • 支援在類中定義函式, 如靜態函式和例項函式
    • 還可以在方法中定義方法(巢狀方法或者區域性方法)
  • 類似的,Dart支援頂級變數,以及依賴於類或物件(靜態變數和例項變數)變數。例項變數有時被稱為域或屬性
  • Dart不具備關鍵字publicprotectedprivate。如果一個識別符號以下劃線(_)開始,那麼它和它的庫都是私有的
  • 識別符號可以字母或(_)開始,或者是字元加數字的組合開頭

以上只是大概說明了一些Dart中的重要概念, 具體的語法使用, 請看下文

基本語法

註釋

Dart的註釋分為3種:單行註釋、多行註釋、文件註釋

  • 單行註釋以//開頭
  • 多行註釋以/*開頭,以*/結尾
  • 文件註釋以///或者/**開頭

分號;

  • 分號用於分隔Dart語句
  • 通常我們在每條可執行的語句結尾新增分號
  • 使用分號的另一用處是在一行中編寫多條語句
  • Dart中,用分號來結束語句是必須的, 不加分則會報錯

其他語法

  • 按照Dart的程式設計規範,使用2個空格來縮排
  • 輸出語句使用print(Object)

變數和常量

變數

使用varObjectdynamic關鍵字宣告變數

var name = 'name';
dynamic name1 = 'name1';
String name2 = 'name2';

// 變數的賦值
name = 'a';
name1 = 'a1';
name2 = 'a2';
複製程式碼

未初始化的變數的初始值為null, 即使是數字也是如此,因為在Dart中數字也是一個物件

var name;
dynamic name1;
String name2;
複製程式碼

可選型別

在宣告變數的時候,你可以選擇加上具體的型別:

String name2 = 'name2';
複製程式碼
  • 這種方式可以更加清晰的表達你想要定義的變數的型別, 編譯器也可以根據該型別為你提供程式碼補全、提前發現 bug 等功能
  • 注意: 對於區域性變數,這裡遵守 程式碼風格推薦 部分的建議,使用var而不是具體的型別來定義區域性變數

常量

  • 常量使用final或者const
  • 一個final變數只能賦值一次
  • 一個const變數是編譯時常量
  • 例項變數可以為final但是不能是const

final

final修飾的變數(即常量2)

  final age = 10;
  final int age1 = 20;

  // final修飾的變數不能重新賦值, 會報錯
  age = 20;
  age1 = 30;
複製程式碼

const

  • const變數為編譯時常量
  • 如果在類中使用const定義常量,請定義為static const
  • 使用const定義的常量, 可以直接給定初始值,也可以使用其他const變數的值來初始化其值
  // const
  const m1 = 12;
  const double m2 = 23;
  const m3 = m1 + m2;

  // final修飾的變數不能重新賦值, 會報錯
  m1 = 10;
  m2 = 1.02;
複製程式碼

操作符

算術操作符

Dart支援常用的算術操作符

操作符 解釋
+ 加號
減號
-expr 負號
* 乘號
/ 除號(值為double型別)
~/ 除號,但是返回值為整數
% 取模

示例:

assert(2 + 3 == 5);
assert(2 - 3 == -1);
assert(2 * 3 == 6);
assert(5 / 2 == 2.5);   // 結果是double型別
assert(5 ~/ 2 == 2);    // 結果是integer型別 
assert(5 % 2 == 1);     // 餘數
複製程式碼

自加自減

Dart還支援自加自減操作

  • ++var: 先自加在使用
  • var++: 先使用在自加
  • --var: 先自減在使用
  • var--: 先使用在自減

示例

  var a = 0, b = 0;
  
  b = a++;
  print('a = $a, b = $b'); //a = 1, b = 0
  b = ++a;
  print('a = $a, b = $b'); //a = 2, b = 2


  b = a--;
  print('a = $a, b = $b'); //a = 1, b = 2
  b = --a;
  print('a = $a, b = $b'); //a = 0, b = 0
複製程式碼

關係操作符

運算子 含義
== 等於
!= 不等於
> 大於
< 小於
>= 大於等於
<= 小於等於
  • 要測試兩個物件代表的是否為同樣的內容,使用 == 操作符
  • 在某些情況下,你需要知道兩個物件是否是同一個物件, 使用identical()方法
external bool identical(Object a, Object b);
複製程式碼

型別判定操作符

型別判定操作符是在執行時判定物件型別的操作符

操作符 解釋
as 型別轉換
is 如果物件是指定的型別返回 True
is! 如果物件是指定的型別返回 False
  • 只有當obj實現了 T 的介面, obj is T 才是true。例如obj is Object總是true
  • 使用as操作符把物件轉換為特定的型別
  • 可以把as它當做用is判定型別然後呼叫 所判定物件的函式的縮寫形式
if (emp is Person) { // Type check
  emp.firstName = 'Bob';
}

// 上面程式碼可簡化為
(emp as Person).firstName = 'Bob';
複製程式碼

注意: 如果empnull或者不是Person型別,則第一個示例使用is則不會執行條件裡面的程式碼,而第二個情況使用as則會丟擲一個異常; 所以在不缺定emp是否為空的情況下, 安全起見, 建議使用第一種方式

賦值操作符

= –= /= %= >>= ^=
+= *= ~/= <<= &=

示例:

// 給 a 變數賦值
a = value;  

// 複合賦值操作符
a += b;  // 等價於a = a + b;

// 如果 b 是 null,則賦值給 b;
// 如果不是 null,則 b 的值保持不變
b ??= value; 
     
// 如下所示:     
  var s;
  print(s);  // null
  print(s ?? 'str');  // str
  s ??= 'string';
  print(s);  // string
複製程式碼

邏輯操作符

可以使用邏輯操作符來 操作布林值:

  • !expr: 對錶達式結果取反(true 變為 false ,false 變為 true)
  • ||: 邏輯 OR
  • &&: 邏輯 AND

條件表示式

condition ? expr1 : expr2
// 如果 condition 是 true,執行 expr1 (並返回執行的結果); 否則執行 expr2 並返回其結果

expr1 ?? expr2
// 如果 expr1 是 non-null,返回其值; 否則執行 expr2 並返回其結果
複製程式碼

示例:

String toString() => msg ?? super.toString();

// 上面的程式碼等價於
String toString() => msg == null ? super.toString() : msg;

// 等價於
String toString() {
  if (msg == null) {
    return super.toString();
  } else {
    return msg;
  }
}
複製程式碼

級聯操作符

級聯操作符 (..) 可以在同一個物件上 連續呼叫多個函式以及訪問成員變數。 使用級聯操作符可以避免建立 臨時變數, 並且寫出來的程式碼看起來 更加流暢

querySelector('#button') // Get an object.
  ..text = 'Confirm'   // Use its members.
  ..classes.add('important')
  ..onClick.listen((e) => window.alert('Confirmed!'));
複製程式碼

第一個方法querySelector()返回了一個selector物件。 後面的級聯操作符都是呼叫這個物件的成員, 並忽略每個操作 所返回的值

// 上面程式碼等價於
var button = querySelector('#button');
button.text = 'Confirm';
button.classes.add('important');
button.onClick.listen((e) => window.alert('Confirmed!'));
複製程式碼

級聯呼叫也可以巢狀:

final addressBook = (new AddressBookBuilder()
      ..name = 'jenny'
      ..email = 'jenny@example.com'
      ..phone = (new PhoneNumberBuilder()
            ..number = '415-555-0100'
            ..label = 'home')
          .build())
    .build();
複製程式碼

注意:嚴格來說,兩個點的級聯語法不是一個操作符, 只是一個Dart特殊語法。

流程控制語句

Dart中可以使用下面的語句來控制Dart程式碼的流程:

  • if-else
  • forfor-in
  • whiledo-while
  • switch
  • assert
  • breakcontinue
  • try-catchthrow

if-else

Dart支援if語句以及可選的else

  if (a == 0) {
    print('a = 0');
  } else if (a == 1) {
    print('a = 1');
  } else {
    print('a = 2');
  }
複製程式碼

注意點: 上述程式碼中的條件控制語句的結果必須是布林值

for

可以使用標準的for迴圈, ListSet等實現了Iterable介面的類還支援for-in形式的遍歷:

  var arr = [0, 1, 2];

  // for迴圈
  for (var i = 0; i < arr.length; i++) {
    print(arr[i]);
  }
  
  // for-in迴圈
  for (var x in arr) {
    print(x);
  }
複製程式碼

Whiledo-while

  // while 迴圈在執行迴圈之前先判斷條件是否滿足:
  while (c == 0) {
    print('c = $c');
  }

  // 而do-while迴圈是先執行迴圈程式碼再判斷條件:
  do {
    print('c = $c');
  } while (c == 0);
複製程式碼

Breakcontinue

使用break來終止迴圈:

while (true) {
  if (shutDownRequested()) break;
  processIncomingRequests();
}
複製程式碼

使用continue來開始下一次迴圈

for (int i = 0; i < candidates.length; i++) {
  var candidate = candidates[i];
  if (candidate.yearsExperience < 5) {
    continue;
  }
  candidate.interview();
}
複製程式碼

Switch

  • Dart中的Switch語句使用 == 比較 integerstring、或者編譯時常量
  • 比較的物件必須都是同一個類的例項, 比較適合列舉值
  • 每個非空的case語句都必須有一個break語句
  • 另外還可以通過continuethrow或者return來結束非空case語句
  • 當沒有case語句匹配的時候,可以使用default語句來匹配這種預設情況
  • 每個case語句可以有區域性變數,區域性變數只有在這個語句內可見
  var command = 'OPEN';
  switch (command) {
    case 'CLOSED':
      print('CLOSED');
      break;
    case 'APPROVED':
      print('APPROVED');
      // break;
      // 這裡非空的case, 沒有break會報錯
    case 'DENIED':
      // 這裡空的case, 可以不要break
    case 'OPEN':
      print('OPEN');
      continue nowClosed;
  //如果你需要實現這種繼續到下一個 case 語句中繼續執行,則可以 使用 continue 語句跳轉到對應的標籤(label)處繼續執行:
  nowClosed:
    case 'PENDING':
      print('PENDING');
      break;
    default:
      print('default');
  }
複製程式碼

Assert

  • 斷言: 如果條件表示式結果不滿足需要,則可以使用assert 語句中斷程式碼的執行
  • assert方法的引數可以為任何返回布林值的表示式或者方法。
  • 如果返回的值為true,斷言執行通過,執行結束
  • 如果返回值為false,斷言執行失敗,會丟擲一個異常
  • 可在開發過程中, 監測程式碼是否有問題時使用
// 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的基本資料型別

參考文獻


相關文章