Try   HackMD

Dart 語言:宣告、數據類型、操作符

Overview of Content

認識 Dart 語言

Dart 是單線程(單執行序),GC 回收使用 CMS 機制,也就是使用分代回收機制 (新生代、老年代)

以下會以 Java 語言進行比較,提及與 Java 的差異,Dart 與 Groovy 也有部分相像

// 先來個 Hello World 起手 void main() { print('Hello World'); }

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

  • 使用指令運行,該指令存在於 Flutter SDK 的資料夾內,將該路徑加入環境變數,重啟 AS 就可以在終端機下達指令 dart xxx.dart

    Dart 指令路徑: ${flutter_sdk}\bin\cache\dart-sdk\bin

Dart 語言、程式特性

  • Dart 語言的特性

    1. 所有的東西都是物件,甚至包含 Java 的基礎類型 (eg. int)

    2. Dart 是弱類型語言,不必指定數據類型

    3. 指定數據類型、const 常量可以提高運行速度

    4. Dart 是 AOT (Ahead Of Time) 編譯,在安裝前會先進行預編譯,編譯成本地代碼 (Dart to java or object-c)

    5. Dart 也可以 JIN (Just In Time) 編譯

    6. 以 60fps 運行的流暢動畫和轉場,可以在沒有鎖的時候進行物件分配 & 垃圾回收,Dart 避免了線程的搶佔 (線程的特性與 Java 不同)

    7. 代碼即是布局,不須另外使用另一個語言建構 (Android 使用 Xml 建構)

  • Dart 程式特性

    1. 統一的程序入口 main(),這一點如同 C、Java 語言

    2. 並沒有 publicprotectedprivate 的參數訪問限制概念,但 私有可以變量可以使用下滑線 ( _ ) 來表示

      ​​​​​​​​int hello; ​​​​​​​​int _hello; // 私有
    3. 支持異步處理 anync/ await

    4. 所有函數都有函數返回值! 如果沒有返回值默認返回為 null

Dart 常用庫

  • Dart 中常見的第三方庫有如下表所示:

    庫名 描述
    dart:async 異步編成支持,提供 Future & Stream
    dart:collection 針對 dart:core 提供更多的集合支持
    dart:convert 不同類型(JSONUTF-8) 的字符轉換
    dart:core 基礎核心庫
    dart:html 網頁開發用到的庫
    dart:io 文件讀取的 IO
    dart:math 函數、隨機算法等等
    dart:svg SVG 動畫

Dart 變數宣告

Dart 變數有幾個特色

  1. Dart 可使用「中文」命名 (但不建議)
  2. Dart 語言中所有的東西都是物件,並沒有基礎類型的概念

宣告變數:Object / var / dynamic

  • 一般我們在宣告類別時必須寫清楚類型,而 dart 可以直接使用 var 作為類型宣告 (Dart 的編碼風格),在 Java 10kotlin 中也有 var

    宣告方式 解釋 Example
    類型宣告 如同一般 Java 宣告,必須寫清楚是哪種類型的數據(之後會一一介紹 Dart 的類型) Person person = new Person();
    Object 任意類型 Object person = new Person();
    var 自動推導類型 (若是不清楚就要考慮少用),並且推倒後就不可以在更改類型 var person = new Person();
    dynamic 運行時確定數據類型,相對來說會慢一些,在沒有初始化時默認為 null dynamic person = new Person();
  • 其中較為特別的是 dynamic 類型它不在編譯期間定義,它在「運行期間才決定類型」;以下是不同宣告方式的範例

    ​​​​void main() { ​​​​ print('Hello World'); ​​​​ // 使用 Object 宣告 ​​​​ Object o1 = 1; ​​​​ o1 = "1"; ​​​​ ​​​​ // 使用 var 宣告 ​​​​ var v1 = 1; ​​​​ //v1 = "1"; // v1 已定型不可再改(自動推導) ​​​​ ​​​​ // 使用 var 宣告 ​​​​ var v2; ​​​​ v2 = 1; ​​​​ v2 = "1"; // 兩個完全不同物件,v2 類似於 const 指標 ​​​​ ​​​​ // 使用 dynamic 宣告 ​​​​ dynamic d1 = 1; // 與 Object 差異是 dynamic 是在運行時確定 ​​​​ d1 = "1"; ​​​​ Object name1 = 'Alien'; ​​​​ var name2 = 'Pan'; ​​​​ dynamic name3 = 'Kyle'; ​​​​ print("$name1, $name2, $name3"); ​​​​} ​​​​// 函數入參,未聲明就是動態類型 dynamic,如下 ​​​​void testPrint(a) { ​​​​} ​​​​void testPrint2(dynamic a) { ​​​​}

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

    • 不同語言的 var 所造成的差異(編譯期間)

      • 在 JS 中也有 var 這種宣告方式,但 JS 是「動態類型語言」(python 也是),可在賦予值後重新設定不同的類型

        ​​​​​​​​​​​​// JS ​​​​​​​​​​​​var k = "Hello JS" ​​​​​​​​​​​​k = 3; // okay
      • Dart 則是「靜態類型語言」,在賦值時就被定義(自動推倒)

        ​​​​​​​​​​​​// Dart 在賦值時就被定義類型 ​​​​​​​​​​​​var k = "Hello Dart"; ​​​​​​​​​​​​k = 10; // Err !!! ​​​​​​​​​​​​var j; // 尚未被定義就是 null 也就是 object ​​​​​​​​​​​​j = "Hello Dart"; ​​​​​​​​​​​​j = 20; // Okay !!!

final & const 描述

  • Java 中我們可以看到 finalC/C++ 中可以看到 const 描述,其實被這兩者描述過後,該變數都會變為不可再修改的值 (轉為常數),而 final、const 仍然存在著差異

    描述 作用時 範例
    final 運行期間 確定 final String FINAL_NAME = "Apple"
    const 編譯期間 確定 const String CONST_NAME = "Banana"
    ​​​​void main() { ​​​​ final String FINAL_NAME = "Apple"; ​​​​ const String CONST_NAME = "Banana"; ​​​​ //const String TEMP = FINAL_NAME; // Err: 運行時確定 ​​​​ final String TEMP_2 = CONST_NAME; // okay ​​​​} ​​​​class MyClass { ​​​​ final String TAG_1 = "MyClass"; ​​​​ // const String TAG_2 = "MyClass"; // Err: 如同 C++ 的 const 概念使用 ​​​​ // const 定義在類中,必須使用 static 描述 -> static const ​​​​ static const String TAG_3 = "MyClass"; ​​​​}
    • 運行時 final 不可以賦予給編譯時常量 const,因為 const 必須編譯期就確定,而相反操作過來就可以,因為 final 運行時再確認即可

      所以被 const 描述的稱之為常量,它的效能往往會比被 final 描述的更好,因為它在編譯過後就被確定類型

    • const & final 不可以跟 var 一起使用

Dart 數據類型

  • Dart 是屬於 強類型語言,並且 沒有基礎數據類型 (Java 有 8 大基礎數據),intlong都是實體的物件,下圖是 dart 語言的 int 類

  • Dart 有內置的七種類型 (7 個仍是類)

    內置類 介紹 & Java 比較 範例
    num 分為整數、浮點數 int、double
    String 儲存大小為 UTF-16,可用單、雙引號,並可嵌套使用 (省去跳脫字元 \) String str = 'A' or "B"
    bool 如同 Java 使用 bool y = false;
    List<E> 不使用 ArrayList,可直接使用 index 取值,增加數值使用 add List list = new List(1); var list = List(1);
    Map<K, V> 一樣是 Key & Value 相對,取值方式可以使用中括號 []中括號內是放置 key 並非 index Map map = ['A': 1, 'B': 2]
    Runes Unicode 字符,將 32 位的 Unicode 編碼轉為字符串 var a = '\u{1f9f99}'
    Symbol 可以看做 C/C++ 的宏,編譯時的常量 Symbol #Hello

num 類型

  • num 所有數的父類,有 int & double 兩個子類 (但是並無 shortfloatlong 其他數據類型)

    num

    int

    double

    • Dart 與 Java 語言對於數字類型的看待、差異

      1. Dart 只有 int(整) & double(浮點數),而沒有 float、short

      2. 數字類型佔用字節數(byte)的差異:int 在 java 中占用 4 個字節,dart 則會依照平台而改變,屬於動態改變自節數

        ​​​​​​​​​​​​// Dart ​​​​​​​​​​​​int i = 2; ​​​​​​​​​​​​print('int cost byte: ${i.bitLength}'); // 可看當前需要多少個 bit

String 類型:String 陷阱,代碼點、代碼單元

  • String 類對於高級語言來說是個大家都通認的類型,這邊就不過多介紹,主要來比較一下 Dart 與 Java 語言對於 String 類型不同的地方

    1. 基礎差異:總體來說比起 Java 使用起來更加的自由

      • Dart 對於字串的解釋方式可以使用「字符串插值」(String Interpolation),不再像是 Java 只能透過 + 號來串接字串

      • 可以混用單、雙引號來表達字串

      • 使用 '''""" 可以包裹換行的字串

      • 並且可以透過在字串前添加 r 來告訴 Dart 該字串是「元數據」(不需要解譯跳脫字符等等)

      ​​​​​​​​void testString() { ​​​​​​​​ String s1 = "Apple"; ​​​​​​​​ // 使用 ${} 可直接引用其他字串,若是單個詞可省略大括號 {} ​​​​​​​​ String s2 = "This is $s1"; ​​​​​​​​ print(s2); ​​​​​​​​ String s2_1 = 'This is $s1'; // 單、雙引號都可引用,groovy 單引號則不行 ​​​​​​​​ print(s2_1); ​​​​​​​​ // 傳統跳脫字元 `\`,並且可以如同 Java 使用 `+` 號 ​​​​​​​​ String s3 = "This is \"${s1 + "!"}\" "; ​​​​​​​​ print(s3); ​​​​​​​​ // 嵌套使用 ​​​​​​​​ String s4 = 'This is "${s1 + "!"}" '; ​​​​​​​​ print(s4); ​​​​​​​​ // 三個單引號 or 雙引號可以使用換行字串 ​​​​​​​​ String s5 = """ ​​​​​​​​ Hello ​​​​​​​​ World ​​​​​​​​ EveryBody ​​​​​​​​ """; ​​​​​​​​ print(s5); ​​​​​​​​ String s6 = ''' ​​​​​​​​ Apple ​​​​​​​​ Banana ​​​​​​​​ Car ​​​​​​​​ '''; ​​​​​​​​ print(s6); ​​​​​​​​ // 原始字 raw -> r"" ​​​​​​​​ String s7 = r"\n"; // 跳脫字元不起作用 ​​​​​​​​ String s8 = "\n"; ​​​​​​​​ print(s7); ​​​​​​​​ String rType = r"\n"; // r 可輸出元形 "\\n" ​​​​​​​​ print(rType); ​​​​​​​​}

    2. 特殊字元差異

      Java 每個 String 大小不可超過 2 個 byte,若超過則必須分開(這是因為 Java 目前採用 UCS-2 編碼)

      ​​​​​​​​// Java ​​​​​​​​void main() { ​​​​​​​​ String str = "\uA388\uA388"; ​​​​​​​​ println(str); ​​​​​​​​}

      Dart 則可以超過 2 byte,超過只需使用 {} 即可 (若未超過則不用)

      ​​​​​​​​// Dart ​​​​​​​​void main() { ​​​​​​​​ var clapping = '\u{1f44f}'; ​​​​​​​​ print("$clapping"); ​​​​​​​​ var test = '\u1f44f'; // 超過未使用 其實就是 '\u1f44' + 字串 f ​​​​​​​​ print("$test"); ​​​​​​​​ var test2 = '\uf44f'; // 未超過 ​​​​​​​​ print("$test2"); ​​​​​​​​}

    • Dart String 字串長度的陷阱(關鍵字: 代碼點 & 代碼單元)

      代碼單元:String#length 只是大部分是「字符長度」,但並不完全代表代碼單元數量… 假設字符串是以 UTF-16 編碼存儲的(Dart、Java 就是如此),一個代碼單元是 16 位的整數

      代碼點:Unicode 編碼中每個字符對應的一個整數值,也就是儘管超過程式語言的代碼編制長度,也會算成是一個整數值

      範例如下

      ​​​​​​​​void main() { ​​​​​​​​ String testLen = "\u5566\u7788"; ​​​​​​​​ print("${testLen.length}"); ​​​​​​​​}

bool 類型

  • Dart 的 bool 類型與 Java 並無太大的差異(Java use boolean),同樣使用 true/false… 這邊只需要特別注意 對於 Dart 來說 bool 仍是物件,而對於 Java 來講它只是基礎類型

    ​​​​void testBool() { ​​​​ bool flag = false; ​​​​ String msg = flag ? "Hello" : "World"; ​​​​ print(msg); ​​​​}

List 類型

  • Dart 的 List 如同 Array 可以使用下標(index)取值

    以下我們會特別加入 const 的使用,並與 C/C++ 比較 (有相似之處)

    • const 如果放在宣告物件的描述,會讓該物件的引用、內容皆不可修改

    • 但如果 const 只放在建立物件實例的描述,則該物件的引用可以修改,而物件的實例內容則不能修改!

      ​​​​​​​​void testList() { ​​​​​​​​// 創建方法 1 ​​​​​​​​ List list1 = new List(); ​​​​​​​​// 創建方法 2,省略 new ​​​​​​​​ List list2 = List(); ​​​​​​​​// 創建方法 3 ​​​​​​​​ List list3 = [0,1,2,3]; ​​​​​​​​// 下標 index 取值 ​​​​​​​​ print("list3[1]: ${list3[1]}"); ​​​​​​​​ list3.add(44); ​​​​​​​​ print("list3[4]: ${list3[4]}"); ​​​​​​​​ // 1. const 修飾引用 & 內容 ​​​​​​​​ const List list4 = [1,3,5,7,9]; ​​​​​​​​// list4.add(123); Err: 編譯期間會錯誤 ​​​​​​​​// list4[3] = 10; Err: 內容也會被修飾 ​​​​​​​​// list4 = list3; Err: 引用指標也會被修飾 ​​​​​​​​ // 2. const 修飾內容 ​​​​​​​​ List list5 = const [9,7,5,3,1]; ​​​​​​​​ print(list5); ​​​​​​​​ list5 = list4; // 指標未被修飾,可以修改引用指標 ​​​​​​​​// list5[0] = 333; Err: const 修飾內容 ​​​​​​​​ // list5.add(55); Err: const 修飾內容 ​​​​​​​​ print(list5); ​​​​​​​​}

      • 我們可以使用 C/C++ 的 const 修飾指標來表達相同的功效,這樣會看的更加清晰(當然這是對於學過 C/C++ 的人來說會看出兩者個相同之處)

        ​​​​​​​​​​​​#include <stdio.h> ​​​​​​​​​​​​int main() ​​​​​​​​​​​​{ ​​​​​​​​​​​​ int a = 10; int aa = 20; ​​​​​​​​​​​​ int * b = &a; // 一般指標 ​​​​​​​​​​​​ printf("b = %i\n", *b); ​​​​​​​​​​​​ const int * c = &a; // const 修飾內容 ​​​​​​​​​​​​ // *c = 20; Err 內容不可改 ​​​​​​​​​​​​ printf("c = %i\n", *c); ​​​​​​​​​​​​ c = &aa; // 指標可改 ​​​​​​​​​​​​ printf("change, c = %i\n", *c); ​​​​​​​​​​​​ int * const d = &a; // const 修飾指標 ​​​​​​​​​​​​ *d = 20; // 內容可改 ​​​​​​​​​​​​ printf("d = %i\n", *d); ​​​​​​​​​​​​ // d = &aa; // 指標不可改 ​​​​​​​​​​​​ printf("change, d = %i\n", *d); ​​​​​​​​​​​​ const int* const e = &a; // const 修飾指標 & 內容 ​​​​​​​​​​​​ printf("e = %i\n", *e); ​​​​​​​​​​​​ return 0; ​​​​​​​​​​​​}

Map 類型

  • Map 使用跟 List 相似,也可以使用 const 修改(這裡就不特別說明 const 描述的位置造成的差異),特點是 可以使用 [] 自動拓展,不需要像是 Java 使用 put() 函數做添加

    ​​​​void testMap() { ​​​​ // Map 創建方法 1 ​​​​ Map map1 = new Map(); ​​​​ // Map 創建方法 2 ​​​​ Map map2 = Map(); ​​​​ // Map 創建方法 3 ​​​​ Map map3 = {'A': 1, 'B': 2, 'C': 3}; ​​​​ print("map3[A]: ${map3['A']}"); ​​​​ print("map3[B]: ${map3['B']}"); ​​​​ print("map3[C]: ${map3['C']}"); ​​​​ const Map map5 = {'A': 1}; ​​​​// map5['A'] = 3; ​​​​ var map6 = const {'A': 1}; ​​​​ // 直接"自動"拓展 !!! ​​​​ map3['D'] = 4; ​​​​ print("map3[D]: ${map3['D']}"); ​​​​}

Runes 類型

  • Dart 的 Runes 類型是個特別的類型:

    Dart 特別分出兩個單詞:代碼點代碼單元

    單詞 說明
    代碼點 codePointCount 可以取出目前輸入數的數量,它不會按照字元的 Byte 數量來解釋字串長度
    代碼單元 codeUnits 經過編碼後才返回的 Byte 數量
    ​​​​void testRunes() { ​​​​ // \u{1f44f} 是超過 2Byte 的數據 ​​​​ String str = "\u{1f44f}"; ​​​​ print("String: $str, ${str.length}"); ​​​​ var r = "\u{1f44f}"; ​​​​ print("var: $r"); ​​​​ var clapping = '\u{1f44f}'; // 超過 unsigned 2 Byte 需要使用大括號 {} ​​​​ print(clapping); //👏 ​​​​ // 16位代碼單元 ​​​​ print(clapping.codeUnits); // 超過 16 位[55357, 56399] ​​​​ // 獲得完整的 32 位代碼單元 ​​​​ print(clapping.runes.toList()); //輸出 10 進位 [128079] ​​​​ ​​​​ // 取得 codePointCount ​​​​ print("Code point count: ${clapping.runes.length}"); ​​​​//fromCharCode 根據字節碼(Byte)創建字符串 ​​​​ print( String.fromCharCode(128079)); ​​​​ print( String.fromCharCodes(clapping.runes)); ​​​​ print( String.fromCharCodes([55357, 56399])); ​​​​ print( String.fromCharCode(0x1f44f)); ​​​​ Runes input = new Runes( ​​​​ '\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d}'); ​​​​ print("Runes: " + String.fromCharCodes(input)); ​​​​}

    image

    • Java 如何儲存超過 2Byte 的字串?

      以往 Java String 類型無法放置超過 2Byte 的數據,如果要儲存就要使用 \u 開頭的方式來表達,範例如下

      ​​​​​​​​public static void main(String[] args) { ​​​​​​​​ String over2Byte = "\uD83D\uDC4F"; ​​​​​​​​ System.out.println("length: " + over2Byte.length()); ​​​​​​​​}

      String#length() 方法是在 UCS-2Unicode 的其中一種)編碼下所返回的單元(Byte)數量

      image

Symbol 類型

  • Symbol 標示符號,其概念類似於 C/C++ 的 define 宏概念,它可以用來定義常數;Dart 語言在使用 Symbol 類型時要在常數前加上 # 定義;範例如下…

    ​​​​void testSymbol() { ​​​​ Symbol symbol1 = #Hello; ​​​​ switch(symbol1) { ​​​​ case #Hello: ​​​​ print(symbol1); ​​​​ break; ​​​​ case #World: ​​​​ print("World"); ​​​​ break; ​​​​ } ​​​​ Symbol symbol2 = new Symbol("Book"); ​​​​ print("#Book == symbol2: ${#Book == symbol2}"); ​​​​}

操作符

操作符同樣是比較與 Java 相異、沒有的部分,至於與 Java 相同的操作符就不另外介紹

類型判斷型

  • Dart 的類型判斷可以使用下表的幾個關鍵字

    關鍵字 解釋 & 比較 Java 使用 Dart 使用
    as 類型轉換,Java 使用括號強制轉型 int b = (int)a; int b = a as int;
    is 類型判定,Java 使用 instanceof 判斷 if(a instanceof Person) if(a is instanceof)
    is! 反向判定,注意 ! 使用在後面 if(!(a instanceof Person)) if(a is! instanceof)
    ​​​​void testDecide() { ​​​​ int a = 10; ​​​​ double b = 11.11; ​​​​ // as ​​​​ // int & double 無法互轉 ​​​​ //print("b as int: ${b as int}"); ​​​​ // is ​​​​ if(a is int) { ​​​​ print("a is int"); ​​​​ } ​​​​ // is! ​​​​ if(b is! int) { ​​​​ print("b is not int"); ​​​​ } ​​​​}

賦值操作符 ??=

  • 在 Dart 中以下這些操作符號 =+=-=\=*= 都可以使用,而 有一個較特別的是 ??= 操作符,它會先判斷該物件是否為 null,若為 null 則賦值

    以 Java、Dart 兩種語言來比較:

    ​​​​// 使用 Dart 表達… 若 b == null 則將 value 賦予 b,若有值則不改變 ​​​​b ??= value; ​​​​// 使用 Java 表達… 等同於上 ??= 操作符 ​​​​if(b == null) { ​​​​ b = value; ​​​​}

    操作符 ??= 使用範例如下:

    ​​​​void printMessage(String? msg) { ​​​​ msg ??= "No message"; ​​​​ print(msg); ​​​​} ​​​​void main() { ​​​​ printMessage('Hello world'); ​​​​ printMessage(null); ​​​​}

    image

條件表達式 ??

  • 除了基礎的三元表達式 condition ? todo1 : todo2,Dart 還多了一種 ?? 表達,它會先執行第一個敘述,若第一個敘述反為 null 則執行第二個敘述

    以 Java、Dart 兩種語言來比較:

    ​​​​// 使用 Dart 表達… 先執行 expr1 如果為 null ,則換執行 expr2 返回 ​​​​expr1 ?? expr2 ​​​​// 使用 Java 表達… ​​​​int function() { ​​​​ if(expr1 == null) { ​​​​ return expr2 ​​​​ } ​​​​ return expr1; ​​​​}

    操作符 ?? 使用範例如下:

    ​​​​void printMessage2(String? msg) { ​​​​ print(msg ?? "No message"); ​​​​} ​​​​void main() { ​​​​ printMessage2('Hello world'); ​​​​ printMessage2(null); ​​​​}

    image

安全操作符 .?

  • Dart 提供了安全操作符 .?若物件為 null 則直接返回 null,並不會往下執行函數

    以 Java、Dart 兩種語言來比較:

    ​​​​// 使用 Dart 表達… 如果 expr1 不為 null,則執行 method 方法 ​​​​expr1?.method(); ​​​​// 使用 Java 表達… 功能同上 ​​​​if(expr1 != null) { ​​​​ expr1.method(); ​​​​}

    操作符 .? 使用範例如下:

    ​​​​void printMessage3(String? msg) { ​​​​ final length = msg?.length; ​​​​ print('message len: $length'); ​​​​} ​​​​void main() { ​​​​ printMessage3('using operation `.?`'); ​​​​ printMessage3(null); ​​​​}

    image

級聯操作符 ..

  • 操作符號是 ..,在同一個物件上可以連續調用該物件的函數、成員,可以避免創建臨時變量 (可以使用 C++ 理解,必須透過複製建構函數創造臨時物件進行賦值)

    這種操作尤其可以使用在「建造者 builder 模式

    ​​​​void testLink() { ​​​​ MyBuilder builder = MyBuilder(); // 可省略 new 關鍵字 ​​​​ builder..setName("Alien")..setId(123)..setPhone('456')..show(); ​​​​} ​​​​class MyBuilder { ​​​​ String? _name; ​​​​ int? _id; ​​​​ String? _phone; ​​​​ void setName(String name) { ​​​​ _name = name; ​​​​ // 一般 Java 製作 builder 模式就必須返回此類 this 物件 ​​​​ } ​​​​ void setId(int id) { ​​​​ // 使用級聯則不用 ​​​​ _id = id; ​​​​ } ​​​​ void setPhone(String phone) { ​​​​ // 可接續使用 ​​​​ _phone = phone; ​​​​ } ​​​​ void show() { ​​​​ print('name($_name}), id($_id), phone($_phone)'); ​​​​ } ​​​​}

    image

解構元素 ...

  • Dart 可以透過 ... 符號來「解構列表」的元素,將其轉為個別的元素,範例如下

    ​​​​void main() { ​​​​ var message = ['Hello', 'World', '123']; ​​​​ print(['你好', '世界', '456', ...message]); ​​​​}

    image

Appendix & FAQ

tags: Flutter Dart