目錄

Dart 語言演進

本頁列出 Dart 程式語言的重大變更和新增功能。

若要使用 2.0 之後引入的語言功能,請設定不低於 Dart 首次支援該功能時的發行版本的SDK 限制

例如:若要使用在 2.12 中引入的空值安全,請在 pubspec.yaml 檔案中將 2.12.0 設定為較低的限制。

yaml
environment:
  sdk: '>=2.12.0 <3.0.0'

每個版本中的變更

#

Dart 3.6

#

於 2024 年 12 月 11 日發布 | Dart 3.6 公告

Dart 3.6 為語言新增了對數字分隔符號底線 (_) 的支援。數字分隔符號可以提高長數字常值的可讀性。

dart
var m = 1__000_000__000_000__000_000;

Dart 3.5

#

於 2024 年 8 月 6 日發布 | Dart 3.5 公告

Dart 3.5 沒有新增任何語言功能,但對型別推斷期間考慮的內容進行了微小的變更。這些變更包括以下未進行語言版本化的變更

  • await 運算式的內容是 dynamic 時,運算式運算元的內容現在是 FutureOr<_>
  • 當整個 if-null 運算式 (e1 ?? e2) 的內容是 dynamic 時,e2 的內容現在是 e1 的靜態型別。

Dart 3.4

#

於 2024 年 5 月 14 日發布 | Dart 3.4 公告

Dart 3.4 對型別分析進行了一些改進。這些包括

  • 改進條件運算式、if-null 運算式和賦值以及 switch 運算式的型別分析。
  • 將 cast 模式的模式內容型別結構與規範對齊。
  • 使可為 null 的感知擴展運算子 (...?) 的型別結構對於 map 和 set 常值可為 null,以符合 list 常值的行為。

Dart 3.3

#

於 2024 年 2 月 15 日發布 | Dart 3.3 公告

Dart 3.3 為語言新增了一些增強功能

  • 擴充型別是 Dart 中的一項新功能,可讓您以零成本包裝現有型別。它們類似於包裝類別和擴充方法,但具有不同的實作差異和不同的取捨。

    dart
    extension type Meters(int value) {
      String get label => '${value}m';
      Meters operator +(Meters other) => Meters(value + other.value);
    }
    
    void main() {
      var m = Meters(42); // Has type `Meters`.
      var m2 = m + m; // OK, type `Meters`.
      // int i = m; // Compile-time error, wrong type.
      // m.isEven; // Compile-time error, no such member.
      assert(identical(m, m.value)); // Succeeds.
    }
  • 如果沒有衝突的宣告,抽象 getter 現在可以在私有最終欄位提升的規則下進行提升。

Dart 3.2

#

於 2023 年 11 月 15 日發布 | Dart 3.2 公告

Dart 3.2 為流程分析新增了增強功能,包括

  • 擴展了型別提升以適用於私有最終欄位。先前僅適用於區域變數和參數,現在私有最終欄位可以透過空值檢查和 is 測試提升為不可為 null 的型別。例如,下列程式碼現在是健全的

    dart
    class Example {
      final int? _privateField;
    
      Example(this._privateField);
    
      void f() {
        if (_privateField != null) {
          // _privateField has now been promoted; you can use it without
          // null checking it.
          int i = _privateField; // OK
        }
      }
    }
    
    // Private field promotions also work from outside of the class:
    void f(Example x) {
      if (x._privateField != null) {
        int i = x._privateField; // OK
      }
    }

    如需私有最終欄位何時可以和不能提升的詳細資訊,請查看修正型別提升失敗

  • 修正了在 if-case 陳述式的型別提升行為不一致的問題,其中比對的值會擲回例外狀況。

Dart 3.1

#

於 2023 年 8 月 16 日發布 | Dart 3.1 公告

Dart 3.1 沒有新增任何功能,也沒有對語言進行任何變更。

Dart 3.0

#

於 2023 年 5 月 10 日發布 | Dart 3.0 公告

Dart 3.0 引入了幾個新的主要語言功能

  • 模式,一種新的文法類別,可讓您比對和解構值。
  • 記錄,一種新的型別,可讓您在單一函式傳回中彙總多個不同型別的值。
  • 類別修飾詞,一組新的關鍵字,可讓您控制類別或混入的使用方式。
  • Switch 運算式,一種新的多向分支形式,允許在需要運算式的地方使用。
  • If-case 子句,一種新的條件結構,可將值與模式比對,並根據模式是否比對來執行 then 或 else 分支。

Dart 3.0 也引入了一些破壞性的語言變更

  • 不使用 mixin 類別修飾詞的類別宣告不再能作為混入應用。
  • 如果冒號 (:) 用作選擇性具名參數預設值之前的分隔符號,現在會產生編譯時期錯誤。請改用等號 (=)。
  • 如果 continue 陳述式以未附加到迴圈陳述式 (fordowhile) 或 switch 成員的標籤為目標,現在會產生編譯時期錯誤。

Dart 2.19

#

於 2023 年 1 月 25 日發布

Dart 2.19 引入了一些關於型別推論的注意事項。這些包括:

  • 更多用於不可到達程式碼情況的流程分析標誌。
  • 不再將無法存取的私有名稱委派給 noSuchMethod
  • 頂層型別推論會在循環依賴時拋出錯誤。

Dart 2.19 也引入了對未命名函式庫的支援。用於附加函式庫級別文件註解和註釋的函式庫指令,現在可以而且應該在沒有名稱的情況下撰寫。

dart
/// A really great test library.
@TestOn('browser')
library;

Dart 2.18

#

發布於 2022 年 8 月 30 日 | Dart 2.18 公告

Dart 2.18 增強了型別推論。此變更允許泛型函式呼叫中引數之間的資訊流動。在 2.18 之前,如果您在某些方法中未指定引數的型別,Dart 會回報錯誤。這些型別錯誤會指出潛在的空值發生。透過 2.18,編譯器會從調用中的其他值推斷引數型別。您不需要內聯指定引數型別。

Dart 2.18 也停止支援不繼承 Object 的 mixin 類別。

要了解有關這些功能的更多資訊,請查看:

Dart 2.17

#

發布於 2022 年 5 月 11 日 | Dart 2.17 公告

Dart 2.17 使用增強的列舉擴展了列舉功能。增強的列舉允許列舉宣告定義成員,包括欄位、建構函式、方法、getter 等。

Dart 2.17 在建構函式中新增了對超初始化器參數的支援。超參數可讓您避免必須手動將每個參數傳遞到非重新導向建構函式的超呼叫中。您可以改用超參數將參數轉發到超類建構函式。

Dart 2.17 解除了一些對具名引數的限制。具名引數現在可以與位置引數自由交錯使用。從 Dart 2.17 開始,您可以撰寫以下程式碼:

dart
void main() {
  test(skip: true, 'A test description', () {
    // Very long function body here...
  });
}

要了解有關這些功能的更多資訊,請查看:

Dart 2.16

#

發布於 2022 年 2 月 3 日 | Dart 2.16 公告

Dart 2.16 沒有為 Dart 語言新增任何新功能。它擴展了 Dart 工具。

Dart 2.15

#

發布於 2021 年 12 月 8 日 | Dart 2.15 公告

Dart 2.15 改善了對函式指標的支援,稱為撕裂 (tear-offs)。特別是,現在支援建構函式撕裂。

Dart 2.14

#

發布於 2021 年 9 月 8 日 | Dart 2.14 公告

Dart 2.14 新增了無號位移(或三位移)運算子 (>>>)。這個新運算子的作用類似於 >>,但它始終用零填充最高有效位。

要了解有關這些運算子的更多資訊,請查看位元和位移運算子

Dart 2.14 解除了一些對型別引數的限制。您可以將型別引數傳遞給註釋,並使用泛型函式型別作為型別引數。從 Dart 2.14 開始,您可以撰寫以下程式碼:

dart
@TypeHelper<int>(42, "The meaning")
late List<T Function<T>(T)> idFunctions;
var callback = [<T>(T value) => value];
late S Function<S extends T Function<T>(T)>(S) f;

Dart 2.13

#

發布於 2021 年 5 月 19 日 | Dart 2.13 公告

Dart 2.13 擴展了對型別別名 (typedef) 的支援。型別別名過去僅適用於函式型別,但現在適用於任何型別。您可以使用型別別名建立的新名稱,在可以使用原始型別的任何地方。

Dart 2.13 改進了 Dart FFI 中的結構支援,新增了對內聯陣列和封裝結構的支援。

Dart 2.12

#

發布於 2021 年 3 月 3 日 | Dart 2.12 公告

Dart 2.12 新增了對健全空值安全的支援。當您選擇使用空值安全時,程式碼中的型別預設為不可為空,這表示變數不能包含空值,除非您明確允許。使用空值安全,您的執行階段空值取消引用錯誤會變成編輯時間分析錯誤。

在 Dart 2.12 中,Dart FFI 從 Beta 版畢業到穩定版通道。

Dart 2.10

#

發布於 2020 年 10 月 1 日 | Dart 2.10 公告

Dart 2.10 沒有為 Dart 語言新增任何新功能。

Dart 2.9

#

發布於 2020 年 8 月 5 日

Dart 2.9 沒有為 Dart 語言新增任何新功能。

Dart 2.8

#

發布於 2020 年 5 月 6 日 | Dart 2.8 公告

Dart 2.8 沒有為 Dart 語言新增任何功能。它包含許多準備性的重大變更,以改善空值安全的空值相關可用性和效能。

Dart 2.7

#

發布於 2019 年 12 月 11 日 | Dart 2.7 公告

Dart 2.7 新增了對擴充方法的支援,讓您可以使用簡潔的語法和自動完成體驗,為任何型別(甚至是您無法控制的型別)新增功能,就像常規方法呼叫一樣。

以下範例使用新的 parseInt() 方法擴充 dart:core 中的 String 類別

dart
extension ParseNumbers on String {
  int parseInt() {
    return int.parse(this);
  }
}

void main() {
  int i = '42'.parseInt();
  print(i);
}

Dart 2.6

#

發布於 2019 年 11 月 5 日 | Dart 2.6 公告

Dart 2.6 引入了重大變更 (dart-lang/sdk#37985)。在 Null 作為 FutureOr<T> 的子型別的限制中,現在會產生 Null 作為 T 的解。

例如:以下程式碼現在會印出 Null。在 Dart 2.6 之前,它會印出 dynamic。匿名閉包 () {} 會傳回 Null 型別。

dart
import 'dart:async';

void foo<T>(FutureOr<T> Function() f) { print(T); }

main() { foo(() {}); }

Dart 2.5

#

發布於 2019 年 9 月 10 日 | Dart 2.5 公告

Dart 2.5 沒有為 Dart 語言新增任何功能,但它新增了對從 Dart 程式碼使用新的核心函式庫 dart:ffi 呼叫原生 C 程式碼的支援。

Dart 2.4

#

發布於 2019 年 6 月 27 日

Dart 2.4 引入了一個重大變更 dart-lang/sdk#35097

Dart 現在強制執行超介面中使用的型別變數的共變性。例如:在此版本之前,Dart 接受了以下程式碼,但現在會拒絕:

dart
class A<X> {};
class B<X> extends A<void Function(X)> {};

您現在可以在非同步和產生器函式中使用 async 作為識別碼。

Dart 2.3

#

發布於 2019 年 5 月 8 日 | Dart 2.3 公告

Dart 2.3 新增了三個旨在改善執行清單操作的程式碼(例如宣告式 UI 程式碼)的運算子。

展開運算子可讓您將一個清單中的元素解壓縮到另一個清單中。在以下範例中,buildMainElements() 傳回的清單會被解壓縮到傳遞給 children 引數的清單中。

dart
Widget build(BuildContext context) {
  return Column(children: [
    Header(),
    ...buildMainElements(),
    Footer(),
  ]);
}

集合 if 運算子可讓您有條件地新增元素。以下範例會新增 FlatButton 元素,除非應用程式顯示最後一頁。

dart
Widget build(BuildContext context) {
  return Column(children: [
    Text(mainText),
    if (page != pages.last)
      FlatButton(child: Text('Next')),
  ]);
}

集合 for 運算子可讓您建立重複的元素。以下範例會為 sections 中的每個章節新增一個 HeadingAction 元素。

dart
Widget build(BuildContext context) {
  return Column(children: [
    Text(mainText),
    for (var section in sections)
      HeadingAction(section.heading),
  ]);
}

Dart 2.2

#

發布於 2019 年 2 月 26 日 | Dart 2.2 公告

Dart 2.2 新增了對集合字面值的支援。

dart
const Set<String> currencies = {'EUR', 'USD', 'JPY'};

Dart 2.1

#

發布於 2018 年 11 月 15 日 | Dart 2.1 公告

Dart 2.1 新增了對整數到雙精度數轉換的支援,允許開發人員使用整數字面值設定 double 值。此功能消除了在概念上值為整數時,被迫使用 double 字面值(例如 4.0)的煩惱。

在以下 Flutter 程式碼中,horizontalvertical 的型別為 double

dart
padding: const EdgeInsets.symmetric(
  horizontal: 4,
  vertical: 8,
)

Dart 2.0

#

發布於 2018 年 2 月 22 日 | Dart 2.0 公告

Dart 2.0 實作了新的健全型別系統。在 Dart 2.0 之前,型別並不完全健全,而 Dart 主要依賴執行階段型別檢查。Dart 1.x 程式碼必須移轉到 Dart 2。

語言版本控制

#

單個 Dart SDK 可以同時支援多個版本的 Dart 語言。編譯器會判斷程式碼的目標版本,並根據該版本解譯程式碼。

當 Dart 引入不相容的功能(例如空值安全)時,語言版本控制會變得重要。當 Dart 引入重大變更時,原本可以編譯的程式碼可能不再編譯。語言版本控制可讓您設定每個函式庫的語言版本以維持相容性。

對於空值安全,Dart SDK 2.12 到 2.19 允許您選擇更新程式碼以使用空值安全。Dart 使用語言版本控制來允許非空值安全程式碼與空值安全程式碼一起執行。這個決定可以從非空值安全程式碼移轉到空值安全程式碼。若要檢閱應用程式或套件如何使用不相容的功能移轉到新的語言版本的範例,請查看移轉到空值安全

每個套件都有一個預設語言版本,該版本等於 pubspec.yaml 檔案中 SDK 限制的下限

例如:pubspec.yaml 檔案中的以下項目表示此套件預設為 Dart 2.18 語言版本。

yaml
environment:
  sdk: '>=2.18.0 <3.0.0'

語言版本號碼

#

Dart 將其語言版本格式化為兩個以句點分隔的數字。它讀取為主要版本號碼和次要版本號碼。次要版本號碼可能會引入重大變更。

Dart 版本可能會在語言版本中附加修補程式號碼。修補程式不應變更語言,除非是錯誤修正。例如:Dart 2.18.3 是 Dart 2.18 SDK 語言版本的最新版本。

每個 Dart SDK 都支援其主要版本號碼內的所有語言版本。這表示 Dart SDK 2.18.3 支援 2.0 到 2.18(含)的語言版本,但不支援 Dart 1.x。

從 SDK 版本衍生語言版本表示以下內容:

  • 每當 SDK 的次要版本發布時,就會出現新的語言版本。在實務上,這些語言版本中的許多版本的工作方式與先前版本非常相似,並且它們之間具有完全相容性。例如:Dart 2.9 語言的工作方式與 Dart 2.8 語言非常相似。

  • 當 SDK 的修補程式版本發布時,它不能引入新的語言功能。例如:2.18.3 版本仍然是語言版本 2.18。它必須與 2.18.2、2.18.1 和 2.18.0 相容。

每個函式庫的語言版本選擇

#

依預設,套件中的每個 Dart 檔案都使用相同的語言版本。Dart 將預設語言版本識別為 pubspec.yaml 檔案中指定的 SDK 限制的下限。有時,Dart 檔案可能需要使用較舊的語言版本。例如,您可能無法同時將套件中的所有檔案移轉到空值安全。

Dart 支援每個函式庫的語言版本選取。若要選擇使用與套件其餘部分不同的語言版本,Dart 函式庫必須包含以下格式的註解:

dart
// @dart = <major>.<minor>

例如:

dart
// Description of what's in this file.
// @dart = 2.17
import 'dart:math';
...

@dart 字串必須位於 // 註解中(而非 ////*),並且必須出現在檔案中任何 Dart 程式碼之前。空白字元(tab 和空格)無關緊要,但 @dart 和版本字串內部除外。如先前的範例所示,其他註解可以出現在 @dart 註解之前。

若要了解 Dart 團隊如何以及為何開發這種版本控制方法,請查看語言版本控制規格