跳至主要內容

Dart 語言演進

此頁面列出了 Dart 程式語言的顯著變更和新增內容。

要使用 2.0 後引入的語言特性,請設定不低於 Dart 首次支援該特性版本號的 SDK 約束

例如:要使用 2.12 中引入的空安全,請在 pubspec.yaml 檔案中將 2.12.0 設定為最低約束。

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

每個版本的變化

#

Dart 3.8

#

釋出於 2025 年 5 月 20 日 | Dart 3.8 公告

以下語言特性已新增到 Dart 3.8 中

  • 空感知元素:空感知元素會在集合字面量中評估一個表示式,如果結果不是 null,則將該值插入到周圍的集合中。

以下支援特性已更新

  • Dart format:Dart 3.8 的格式化程式基於先前版本的重寫,整合了反饋、bug 修復和進一步增強。它現在智慧地自動化尾部逗號的放置,決定是否拆分結構而不是強制拆分。更新還包括樣式更改,以收緊和改進程式碼輸出。

有關這些以及其他變更的更多資訊,請參閱Dart 3.8 變更日誌

Dart 3.7

#

釋出於 2025 年 2 月 12 日 | Dart 3.7 公告

Dart 3.7 為語言添加了對萬用字元變數的支援。萬用字元變數是命名為 _ 的區域性變數或引數。萬用字元變數是非繫結的,因此可以多次宣告而不會發生衝突。例如

dart
Foo(_, this._, super._, void _()) {}

從 3.7 開始,dart format 命令也與語言版本關聯。如果輸入檔案的語言版本是 3.7 或更高版本,則程式碼將以新的緊湊風格格式化。

新風格類似於向引數列表新增尾部逗號時獲得的風格,不同之處在於現在格式化程式將為您新增和刪除這些逗號。當引數或引數列表拆分時,格式化如下

dart
longFunction(
  longArgument,
  anotherLongArgument,
);

您可以在變更日誌中找到更多詳情。

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-aware spread 運算子 (...?) 的型別模式對於 map 和 set 字面量可空,以匹配 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 現在可以在私有 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 引入了幾項新的主要語言特性

  • 模式,一種新的語法類別,允許您匹配和解構值。
  • 記錄,一種新型別,允許您將不同型別的多個值聚合到單個函式返回值中。
  • 類修飾符,一組新的關鍵字,允許您控制類或 mixin 的使用方式。
  • Switch 表示式,一種新的多路分支形式,允許在預期表示式的地方使用。
  • If-case 子句,一種新的條件構造,將值與模式匹配,並根據模式是否匹配執行 then 分支或 else 分支。

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

  • 不帶 mixin 類修飾符的類宣告不能再作為 mixins 應用。
  • 如果在可選命名引數的預設值前使用冒號 (:) 作為分隔符,現在會產生編譯時錯誤。請改用等號 (=)。
  • 如果 continue 語句的目標標籤未附在迴圈語句 (for, do, and while) 或 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 的 mixin 類。

要了解有關這些特性的更多資訊,請檢視

Dart 2.17

#

釋出於 2022 年 5 月 11 日 | Dart 2.17 公告

Dart 2.17 透過增強列舉擴充套件了列舉功能。增強列舉允許列舉宣告定義成員,包括欄位、建構函式、方法、getter 等。

Dart 2.17 為建構函式添加了對超初始化引數的支援。超引數允許您避免手動將每個引數傳遞到非重定向建構函式的 super 呼叫中。您可以轉而使用超引數將引數轉發給超類建構函式。

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)的支援。特別是,現在支援建構函式 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 添加了對 健全空安全 的支援。當您選擇加入空安全時,程式碼中的型別預設是非空的,這意味著變數不能包含 null,除非您明確指定可以。有了空安全,您的執行時 null 解引用錯誤將轉變為編輯時分析錯誤。

在 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 添加了對 擴充套件方法 的支援,使您能夠以常規方法呼叫的簡潔性和自動完成體驗為任何型別(即使是您無法控制的型別)新增功能。

以下示例將 dart:core 中的 String 類擴充套件了一個新的 parseInt() 方法

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 添加了對 int 到 double 轉換 的支援,允許開發人員使用整數字面量設定 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 程式碼之前。除了 @dart 和版本字串內部,空白字元(製表符和空格)無關緊要。如上一個示例所示,其他註釋可以出現在 @dart 註釋之前。

要了解 Dart 團隊如何以及為何開發此版本控制方法,請檢視語言版本控制規範