flutter–Dart基礎語法(一)

一、前言

Flutter 是 Google 開源的 UI 工具包,幫助開發者通過一套程式碼庫高效構建多平台精美應用,Flutter 開源、免費,擁有寬鬆的開源協議,支援移動、Web、桌面和嵌入式平台。

Flutter是使用Dart語言開發的跨平台移動UI框架,通過自建繪製引擎,能高性能、高保真地進行Android和IOS開發。Flutter採用Dart語言進行開發,而並非Java,Javascript這類熱門語言,這是Flutter團隊對當前熱門的10多種語言慎重評估後的選擇。因為Dart囊括了多數程式語言的優點,它更符合Flutter構建介面的方式。

本文主要就是簡單梳理一下Dart語言的一些基礎知識和語法。關於程式語言的基本語法無外乎那麼些內容,注釋、變數、數據類型、運算符、流程式控制制、函數、類、異常、文件、非同步、常用庫等內容,相信大部分讀者都是有一定編程基礎的,所以本文就簡單地進行一個梳理,不做詳細的講解。大家也可以參考 Dart程式語言中文網

二、Dart的基本語法

Dart基本語法是指編寫dart程式碼最基本的一些內容、規範,主要包括注釋、變數、數據類型和運算符等內容。

2.1 注釋

Dart 支援單行注釋、多行注釋和文檔注釋。

  • 單行注釋:單行注釋以 // 開始。 所有在 // 和改行結尾之間的內容被編譯器忽略。
    void main() {
      // TODO: refactor into an AbstractLlamaGreetingFactory?
      print('Welcome to my Llama farm!');
    }
  • 多行注釋多行注釋以  /* 開始, 以 */ 結尾。 所有在 /* 和 */ 之間的內容被編譯器忽略 (不會忽略文檔注釋)。 多行注釋可以嵌套。
    void main() {
      /*
       * This is a lot of work. Consider raising chickens.
    
      Llama larry = Llama();
      larry.feed();
      larry.exercise();
      larry.clean();
       */
    }
  • 文檔注釋:文檔注釋可以是多行注釋,也可以是單行注釋, 文檔注釋以 /// 或者 /** 開始。 在連續行上使用 /// 與多行文檔注釋具有相同的效果。在文檔注釋中,除非用中括弧括起來,否則Dart 編譯器會忽略所有文本。 使用中括弧可以引用類、 方法、 欄位、 頂級變數、 函數、 和參數。 括弧中的符號會在已記錄的程式元素的詞法域中進行解析。下面是一個引用其他類和成員的文檔注釋,在生成的文檔中,[Food] 會成為一個鏈接, 指向 Food 類的 API 文檔。
    /// A domesticated South American camelid (Lama glama).
    ///
    /// 自從西班牙時代以來,
    /// 安第斯文化就將駱駝當做肉食類和運輸類動物。
    class Llama {
      String name;
    
      /// 餵養駱駝 [Food].
      ///
      /// 典型的美洲駝每周吃一捆乾草。
      void feed(Food food) {
        // ...
      }
    
      /// 使用 [activity] 訓練駱駝
      /// [timeLimit] 分鐘。
      void exercise(Activity activity, int timeLimit) {
        // ...
      }
    }

2.2 變數

任何保存在變數中的都是一個 對象 , 並且所有的對象都是對應一個  的實例。 無論是數字,函數和 null都是對象。所有對象繼承自Object 類。儘管 Dart 是強類型的,但是 Dart 可以推斷類型,所以類型注釋是可選的。 如果要明確說明不需要任何類型, 需要使用特殊類型 dynamic 。

2.2.1 創建變數

var name = 'Bob';

變數僅存儲對象引用,這裡的變數是 name 存儲了一個 String 類型的對象引用。 「Bob」 是這個 String 類型對象的值。

name 變數的類型被推斷為 String 。 但是也可以通過指定類型的方式,來改變變數類型。 如果對象不限定為單個類型,可以指定為 對象類型 或 動態類型

//指定為動態類型
dynamic name = 'Bob';
//顯示指定為字元串類型
String name = 'Bob';

2.2.2 默認值

未初始化的變數默認值是 null。即使變數是數字 類型默認值也是 null,因為在 Dart 中一切都是對象,數字類型 也不例外。

int lineCount;
assert(lineCount == null); //結果為true 

提示: 在生產環境程式碼中 assert() 函數會被忽略,不會被調用。 在開發過程中, assert(condition) 會在非 true 的條件下拋出異常。

2.3 常量 Final 和 Const

使用過程中從來不會被修改的值,我們成為常量,可以使用 final 或 const, 而不是 var 或者其他類型。 Final 變數的值只能被設置一次; Const 變數在編譯時就已經固定 (Const 變數 是隱式 Final 的類型.) 。最高級 final 變數或類變數在第一次使用時被初始化。

提示: 實例變數可以是 final 類型但不能是 const 類型。 必須在構造函數體執行之前初始化 final 實例變數 —— 在變數聲明中,參數構造函數中或構造函數的初始化列表中進行初始化。

2.2.1 常量的創建

final name = 'Bob'; // Without a type annotation
final String nickname = 'Bobby';
//final 不能被修改:
name = 'Alice'; // Error: 一個 final 變數只能被設置一次。

如果需要在編譯時就固定變數的值,可以使用 const 類型變數。 如果 Const 變數是類級別的,需要標記為 static const。 在這些地方可以使用在編譯時就已經固定不變的值,字面量的數字和字元串, 固定的變數,或者是用於計算的固定數字:

const bar = 1000000; // 壓力單位 (dynes/cm2)
const double atm = 1.01325 * bar; // 標準氣壓

// Const 關鍵字不僅可以用於聲明常量變數。 還可以用來創建常量值,以及聲明創建常量值的構造函數。 任何變數都可以擁有常量值。
var foo = const [];
final bar = const []; 
const baz = []; // 聲明 const 的初始化表達式中 const 可以被省略。 比如上面的 baz。  Equivalent to `const []`

//Const 變數的值不可以修改:
baz = [42]; // Error: 常量變數不能賦值修改。

//非 Final , 非 const 的變數是可以被修改的,即使這些變數 曾經引用過 const 值。
foo = [1, 2, 3]; // 曾經引用過 const [] 常量值。

2.2.2 final和const的相同點

1.聲明時必須要賦值

  

2.只能在初始化賦值一次,之後不能重新賦值

3.後面都不能接var關鍵字

4.類型聲明可以忽略,類似 var,可以根據初始化的值推斷出變數類型

2.2.3 final和const的區別

1、final變數的初始值可以在編譯時確定,也可以在運行時確定,cosnt變數的初始值只能是編譯時確定的值,比如當前時間

2.const變數的不可變性是嵌套的,final不是

const a = {'c': 1};
a['c'] = 2;
// 運行結果 Unsupported operation: Cannot set value in unmodifiable Map

3.記憶體中的創建:相同的值,final變數會重複創建,const會引用同一份值

  const a = {'c': 1};
  const b = {'c': 1};
  print(a == b);//true
  final c = {'c': 1};
  final d = {'c': 1};
  print(c == d);//false

2.4 數據類型

Dart 語言支援以下內建類型:

  • Number:數值類型
  • String:字元串類型
  • Boolean:布爾類型
  • List (也被稱為 Array):列表或數組類型
  • Map:字典類型
  • Set:集合類型
  • Rune (用於在字元串中表示 Unicode 字元):
  • Symbol:符號類型

這些類型都可以被初始化為字面量。 例如, 'this is a string' 是一個字元串的字面量, true 是一個布爾的字面量。因為在 Dart 所有的變數終究是一個對象(一個類的實例), 所以變數可以使用 構造涵數 進行初始化。 一些內建類型擁有自己的構造函數。 例如, 通過 Map() 來構造一個 map 變數。

2.4.1 Number

Dart 語言的 Number 有兩種類型:

  • int:整數值不大於64位, 具體取決於平台。 在 Dart VM 上, 值的範圍從 -263到 263 – 1. Dart 被編譯為 JavaScript 時,使用 JavaScript numbers, 值的範圍從 -253 到 253 – 1.
  • double:64位(雙精度)浮點數,依據 IEEE 754 標準。

int 和 double 都是 num. 的亞類型。 num 類型包括基本運算 +, -, /, 和 *, 以及 abs() ceil(), 和 floor(), 等函數方法。 (按位運算符,例如»,定義在 int 類中。) 如果 num 及其亞類型找不到你想要的方法, 嘗試查找使用 dart:math 庫。

// 整數類型不包含小數點。 下面是定義整數類型字面量的例子:
var x = 1;
var hex = 0xDEADBEEF;

// 如果一個數字包含小數點,那麼就是小數類型。 下面是定義小數類型字面量的例子: var y = 1.1; var exponents = 1.42e5;
// 從 Dart 2.1 開始,必要的時候 int 字面量會自動轉換成 double 類型。 double z = 1; // 相當於 double z = 1.0. //版本提示: 在dart 2.1 之前,在 double 上下文中使用 int 字面量是錯誤的。 //以下是將字元串轉換為數字的方法,反之亦然: // 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 msPerSecond = 1000; const secondsUntilRetry = 5; const msUntilRetry = secondsUntilRetry * msPerSecond;

2.4.2 String

Dart 字元串是一組 UTF-16 單元序列。 字元串通過單引號或者雙引號創建。

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.";

字元串可以通過 ${expression} 的方式內嵌表達式。 如果表達式是一個標識符,則 {} 可以省略。 在 Dart 中通過調用就對象的 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!');

提示: == 運算符用來測試兩個對象是否相等。 在字元串中,如果兩個字元串包含了相同的編碼序列,那麼這兩個字元串相等。

此外,還有字元串的拼接和多行字元串等用法

// 用 + 運算符來把多個字元串連接為一個,也可以把多個字面量字元串寫在一起來實現字元串連接:
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 前綴,可以創建 「原始 raw」 字元串: var s = r"In a raw string, even \n isn't special.";

**一個編譯時常量的字面量字元串中,如果存在插值表達式,表達式內容也是編譯時常量, 那麼該字元串依舊是編譯時常量。 插入的常量值類型可以是 null,數值,字元串或布爾值

// const 類型數據
const aConstNum = 0;
const aConstBool = true;
const aConstString = 'a constant string';

// 非 const 類型數據
var aNum = 0;
var aBool = true;
var aString = 'a string';
const aConstList = [1, 2, 3];

const validConstString = '$aConstNum $aConstBool $aConstString'; //const 類型數據
// const invalidConstString = '$aNum $aBool $aString $aConstList'; //非 const 類型數據,error Not a constant expression.

2.4.3 Boolean

Dart 使用 bool 類型表示布爾值。 Dart 只有字面量 true、false 是布爾類型, 這兩個對象都是編譯時常量。

Dart 的類型安全意味著不能使用 if (nonbooleanValue) 或者 assert (nonbooleanValue)。 而是應該像下面這樣,明確的進行值檢查:

// 檢查空字元串。
var fullName = '';
assert(fullName.isEmpty);

// 檢查 0 值。
var hitPoints = 0;
assert(hitPoints <= 0);

// 檢查 null 值。
var unicorn;
assert(unicorn == null);

// 檢查 NaN 。
var iMeantToDoThis = 0 / 0;
assert(iMeantToDoThis.isNaN);

2.4.4 List

幾乎每種程式語言中最常見的集合可能是 array 或有序的對象集合。 在 Dart 中的 Array 就是 List 對象, 通常稱之為 List 。 下面是一個 Dart List 的示例:

var list = [1, 2, 3];

提示: Dart 推斷 list 的類型為 List<int> 。 如果嘗試將非整數對象添加到此 List 中, 則分析器或運行時會引發錯誤。 

Lists 的下標索引從 0 開始,第一個元素的索引是 0。 list.length – 1 是最後一個元素的索引。 

var list = [1, 2, 3];
assert(list.length == 3);
assert(list[1] == 2);

list[1] = 1;
assert(list[1] == 1);

//在 List 字面量之前添加 const 關鍵字,可以定義 List 類型的編譯時常量
var constantList = const [1, 2, 3];
// constantList[1] = 1; // 取消注釋會引起錯誤。

List 類型包含了很多 List 的操作函數。 更多資訊參考 泛型 和 集合.

2.4.5 Set

在 Dart 中 Set 是一個元素唯一且無序的集合。 Dart 為 Set 提供了 Set 字面量和 Set 類型。

版本提示: 雖然 Set 類型 一直是 Dart 的核心部分, 但在 Dart2.2 中才引入了 Set 字面量 。

下面是通過字面量創建 Set 的一個簡單示例:

var halogens = {'fluorine', 'chlorine', 'bromine', 'iodine', 'astatine'};

Note: Dart 推斷 halogens 類型為 Set<String> 。如果嘗試為它添加一個 錯誤類型的值,分析器或執行時會拋出錯誤。

要創建一個空集,使用前面帶有類型參數的 {} ,或者將 {} 賦值給 Set 類型的變數:

var names = <String>{};
// Set<String> names = {}; // 這樣也是可以的。
// var names = {}; // 這樣會創建一個 Map ,而不是 Set 。

是 Set 還是 Map ? Map 字面量語法同 Set 字面量語法非常相似。 因為先有的 Map 字母量語法,所以 {} 默認是 Map 類型。   如果忘記在 {} 上注釋類型或賦值到一個未聲明類型的變數上,   那麼 Dart 會創建一個類型為 Map<dynamic, dynamic> 的對象。

// 使用 add() 或 addAll() 為已有的 Set 添加元素:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);

// 使用 .length 來獲取 Set 中元素的個數:
var elements = <String>{};
elements.add('fluorine');
elements.addAll(halogens);
assert(elements.length == 5);

// 在 Set 字面量前增加 const ,來創建一個編譯時 Set 常量:
final constantSet = const {
  'fluorine',
  'chlorine',
  'bromine',
  'iodine',
  'astatine',
};
// constantSet.add('helium'); // Uncommenting this causes an error.

更多關於 Set 的內容,參閱 Generic 及 Set

2.4.6 Map

通常來說, Map 是用來關聯 keys 和 values 的對象。 keys 和 values 可以是任何類型的對象。在一個 Map 對象中一個 key 只能出現一次。 但是 value 可以出現多次。 Dart 中 Map 通過 Map 字面量 和 Map 類型來實現。下面是使用 Map 字面量的兩個簡單例子:

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 的類型推斷為 Map<int, String> 。 如果嘗試在上面的 map 中添加錯誤類型,那麼分析器或者運行時會引發錯誤。

以上 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() ,而不是使用 new Map()。 因為在 Dart 2 中,new 關鍵字是可選的。 

// 添加 key-value 對到已有的 Map 中:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds'; // Add a key-value pair

// 從一個 Map 中獲取一個 value:
var gifts = {'first': 'partridge'};
assert(gifts['first'] == 'partridge');

// 如果 Map 中不包含所要查找的 key,那麼 Map 返回 null:
var gifts = {'first': 'partridge'};
assert(gifts['fifth'] == null);

// 使用 .length 函數獲取當前 Map 中的 key-value 對數量:
var gifts = {'first': 'partridge'};
gifts['fourth'] = 'calling birds';
assert(gifts.length == 2);

// 創建 Map 類型運行時常量,要在 Map 字面量前加上關鍵字 const。
final constantMap = const {
  2: 'helium',
  10: 'neon',
  18: 'argon',
};

// constantMap[2] = 'Helium'; // 取消注釋會引起錯誤。

更名多關於 Map 的內容,參考 Generics and Maps.

2.4.7 Rune

在 Dart 中, Rune 用來表示字元串中的 UTF-32 編碼字元

Unicode 定義了一個全球的書寫系統編碼, 系統中使用的所有字母,數字和符號都對應唯一的數值編碼。 由於 Dart 字元串是一系列 UTF-16 編碼單元, 因此要在字元串中表示32位 Unicode 值需要特殊語法支援。

表示 Unicode 編碼的常用方法是, \uXXXX, 這裡 XXXX 是一個4位的16進位數。 例如,心形符號 (♥) 是 \u2665。 對於特殊的非 4 個數值的情況, 把編碼值放到大括弧中即可。 例如,emoji 的笑臉 (�) 是 \u{1f600}

String 類有一些屬性可以獲得 rune 數據。 屬性 codeUnitAt 和 codeUnit 返回16位編碼數據。 屬性 runes 獲取字元串中的 Rune 。

下面是示例演示了 Rune 、 16-bit code units、 和 32-bit code points 之間的關係。 

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));
}

提示: 謹慎使用 list 方式操作 Rune 。 這種方法很容易引發崩潰, 具體原因取決於特定的語言,字符集和操作。

2.4.8 Symbol

一個 Symbol 對象表示 Dart 程式中聲明的運算符或者標識符。 你也許永遠都不需要使用 Symbol ,但要按名稱引用標識符的 API 時, Symbol 就非常有用了。 因為程式碼壓縮後會改變標識符的名稱,但不會改變標識符的符號。 通過字面量 Symbol ,也就是標識符前面添加一個 # 號,來獲取標識符的 Symbol 。

#radix
#bar

Symbol 字面量是編譯時常量。

2.5 運算符

下表是 Dart中定義的運算符,描述的運算符優先順序近似於Dart 解析器實際行為。

描述 運算符
前綴運算符 expr++    expr--    ()    []    .    ?.
後綴運算符 -expr    !expr    ~expr    ++expr    --expr   
倍數運算符 *    /    %  ~/
加減運算符 +    -
移位運算符 <<    >>    >>>
位與 &
位異或 ^
位或 |
關係運算符和測試運算符 >=    >    <=    <    as    is    is!
相等判斷 ==    !=   
邏輯與 &&
邏輯或 ||
判空運算符 ??
條件運算符 expr1 ? expr2 : expr3
級聯運算符 ..
賦值運算符 =    *=    /=   +=   -=   &=   ^=   etc.

創建表達式的時候會用到運算符。 下面是一些運算符表達式的實例:

a++
a + b
a = b
a == b
c ? a : b
a is T

在 運算符表 中, 每一行的運算符優先順序,由上到下依次排列,第一行優先順序最高,最後一行優先順序最低。 例如 %運算符優先順序高於 == , 而 == 高於 &&。 根據優先順序規則,那麼意味著以下兩行程式碼執行的方式相同:

// 括弧可以提高可讀性。
if ((n % i == 0) && (d % i == 0)) ...

// 可讀性差,但是是等效的。
if (n % i == 0 && d % i == 0) ... 

警告: 對於有兩個操作數的運算符,運算符的功能由左邊的操作數決定。 例如, 如果有兩個操作數 Vector 和 Point, aVector + aPoint 使用的是 Vector 中定義的 + 運算符。

下面就對dart中的運算符進行常規意義的分類簡單列舉一下:

  • 算術運算符:+、-、*、/、~/(整除,結果為整數)、%(求余運算)、++(自增)、–(自減)。(++、–分別有前綴和後綴兩種表達形式,大家在學習的過程中要注意他們之間的區別)
    assert(2 + 3 == 5);
    assert(2 - 3 == -1);
    assert(2 * 3 == 6);
    assert(5 / 2 == 2.5); // 結果是雙浮點型
    assert(5 ~/ 2 == 2); // 結果是整型
    assert(5 % 2 == 1); // 餘數
    
    assert('5/2 = ${5 ~/ 2} r ${5 % 2}' == '5/2 = 2 r 1');
  • 關係運算符:==、!=、>、<、>=、<=,都是常規符號,不做其他解釋,大家要注意的是關係運算符的表達式結果為boolean類型。
    assert(2 == 2);
    assert(2 != 3);
    assert(3 > 2);
    assert(2 < 3);
    assert(3 >= 3);
    assert(2 <= 3);
  • 邏輯運算符:&&(邏輯與,短路運算)、||(邏輯或,短路運算)、!。
    //短路運算,即當左邊的表達式結果能確定最終結果時,右邊的表達式不再進行運算
      var a = 10;
      var b = a > 9 || a++ > 10; //a>9成立,又是或運算,所以b的結果為true,右邊的 a++ > 10不會進行計算,所以a的值不會加1
      print(a); //10
  • 賦值運算符:=、+=、-=、*=、/=。。。等一系列的擴展賦值運算符
    var a = 2; // 使用 = 複製
    a *= 3; // 複製並做乘法運算: a = a * 3
    assert(a == 6);
  • 位運算符:&(按位與運算)、|(按位或運算)、^(按位異或運算)、<<(按位左移)、>>(按位右移)。(所有的位運算都是以二進位形式進行的)
    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
  • 條件運算符:
    •  condition ? expr1 : expr2 如果條件為 true, 執行 expr1 (並返回它的值), 否則, 執行並返回 expr2 的值。
    •  expr1 ?? expr2 如果 expr1 是 non-null, 返回 expr1 的值; 否則, 執行並返回 expr2 的值。
  • 級聯運算符(..):可以實現對同一個對像進行一系列的操作。 除了調用函數, 還可以訪問同一對象上的欄位屬性。 這通常可以節省創建臨時變數的步驟, 同時編寫出更流暢的程式碼。嚴格的來講, 「兩個點」 的級聯語法不是一個運算符。 它只是一個 Dart 的特殊語法。
    // 第一句調用函數 querySelector() , 返回獲取到的對象。 獲取的對象依次執行級聯運算符後面的程式碼, 程式碼執行後的返回值會被忽略。
    querySelector('#confirm') // 獲取對象。
      ..text = 'Confirm' // 調用成員變數。
      ..classes.add('important')
      ..onClick.listen((e) => window.alert('Confirmed!'));
    
    // 上面的程式碼等價於:
    var button = querySelector('#confirm');
    button.text = 'Confirm';
    button.classes.add('important');
    button.onClick.listen((e) => window.alert('Confirmed!'));
    
    // 級聯運算符可以嵌套,例如:
    final addressBook = (AddressBookBuilder()
          ..name = 'jenny'
          ..email = '[email protected]'
          ..phone = (PhoneNumberBuilder()
                ..number = '415-555-0100'
                ..label = 'home')
              .build())
        .build();
    
    // 在返回對象的函數中謹慎使用級聯操作符。 例如,下面的程式碼是錯誤的:
    var sb = StringBuffer();
    sb.write('foo')
      ..write('bar'); // Error: 'void' 沒喲定義 'write' 函數。
    // sb.write() 函數調用返回 void, 不能在 void 對象上創建級聯操作。
  • 類型判定運算符:as()、is(判定是否是指定類型或該類型子類的對象)、is! (跟is相反)。
    • 使用 as 運算符將對象強制轉換為特定類型。 通常,可以認為是 is 類型判定後,被判定對象調用函數的一種縮寫形式。 請考慮以下程式碼: 
if (emp is Person) {
  // 類型判斷
  // emp.firstName = 'Bob';

  // 下面這種寫法一般是沒問題的,進行類型強轉
  (emp as Person).firstName = 'Bob';
}

 

 

Tags: