內容

Dart 語言演進

此頁面列出 Dart 程式語言的顯著變更和新增功能。

如要使用 2.0 之後推出的語言功能,請設定 SDK 約束,其版本不得低於 Dart 首次支援該功能的版本。

例如:如要使用 2.12 中推出的 null 安全性,請將 2.12.0 設定為 pubspec.yaml 檔案中的較低約束。

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

各個版本的變更

#

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 現在可以在 私有 final 欄位提升 的規則下進行提升。

Dart 3.2

#

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

Dart 3.2 新增了對流程分析的強化功能,包括

  • 擴充 類型提升 以適用於私有 final 欄位。先前僅適用於區域變數和參數,現在私有 final 欄位可透過 null 檢查和 is 測試提升為非可為空類型。例如,下列程式碼現在是正確的

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

    如需進一步了解私有 final 欄位何時可以提升以及何時無法提升,請查看 修正類型提升失敗

  • 修正 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 會回報錯誤。這些類型錯誤會引述潛在的 null 發生。在 2.18 中,編譯器會從呼叫中的其他值推論引數類型。你不必內嵌指定引數類型。

Dart 2.18 也停止支援未延伸 Object 的混合類別。

若要深入瞭解這些功能,請查看

Dart 2.17

#

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

Dart 2.17 透過增強列舉擴充了列舉功能。增強列舉允許列舉宣告定義包含欄位、建構函式、方法、取得器等的成員。

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 改善了對函式指標(稱為撕裂)的支援。特別是,現在支援建構函式撕裂。

Dart 2.14

#

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

Dart 2.14 新增了無符號位移(或三重位移)運算子 (>>>)。這個新運算子與 >> 的運作方式類似,但它總是會將最高有效位元填入 0。

若要深入瞭解這些運算子,請查看 按位元和位移運算子

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 新增了對健全的 Null 安全性的支援。當您選擇使用 Null 安全性時,您的程式碼中的類型預設為不可為 Null,這表示變數不能包含 Null,除非您明確表示可以。有了 Null 安全性,您的執行時期 Null 取消參考錯誤會轉變為編輯時期分析錯誤。

在 Dart 2.12 中,Dart FFI 從測試版畢業到穩定頻道。

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 語言的新功能。它包含許多準備性的重大變更,以改善Null 安全性相關的可使用性和效能。

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:ffi 從 Dart 程式碼呼叫原生 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 引進不相容功能(例如 Null 安全性)時,語言版本控管變得重要。當 Dart 引進重大變更時,原本可以編譯的程式碼可能無法再編譯。語言版本控管讓你可以設定每個函式庫的語言版本,以維持相容性。

在 Null 安全性的情況下,Dart SDK 2.12 到 2.19 允許你選擇更新程式碼以使用 Null 安全性。Dart 使用語言版本控管,讓非 Null 安全程式碼可以和 Null 安全程式碼一起執行。此決定讓從非 Null 安全程式碼移轉到 Null 安全程式碼成為可能。若要檢閱應用程式或套件如何移轉到具有不相容功能的新語言版本,請查看 移轉到 Null 安全性

每個套件都有預設語言版本,等於 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 檔案可能需要使用較舊的語言版本。例如,你可能無法同時將套件中的所有檔案移轉到 Null 安全性。

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 團隊如何以及為何開發此版本控管方法,請查看 語言版本控管規格