跳到主要內容

Dart 3 遷移指南

Dart 3 是一個主要版本,為 Dart 引入了新的核心功能:記錄模式類別修飾詞

除了這些新功能之外,Dart 3 還包含許多可能會破壞現有程式碼的變更。

本指南將協助您解決升級到 Dart 3後可能遇到的任何遷移問題。

簡介

#

未版本化與版本化變更

#

以下列出的潛在破壞性變更分為兩類

  • 未版本化變更:這些變更會在升級到 Dart 3.0 SDK 或更高版本後影響任何 Dart 程式碼。沒有任何方法可以「關閉」這些變更。

  • 版本化變更:這些變更僅在套件或應用程式的語言版本設定為 >= Dart 3.0 時適用。語言版本衍生自pubspec.yaml 檔案中的 sdk 下限約束。像這樣的 SDK 約束不會套用 Dart 3 版本化變更

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

    但像這樣的 SDK 約束會套用

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

若要使用新的 Dart 3 功能,您必須將語言版本更新為 3.0。這樣您就可以同時獲得 Dart 3 版本化變更。

Dart 3 向後相容性

#

許多使用 Dart 2.12 或更高版本且具有空值安全性的套件和應用程式可能向後相容於 Dart 3。對於 SDK 約束下限為 2.12.0 或更高的任何套件,這都是有可能的。

Dart 的 pub 工具即使上限限制為低於 3.0.0 的版本,也允許解析。例如,具有以下約束的套件將被允許使用 Dart 3.x SDK 進行解析,因為當下限約束為 2.12 或更高時,pub 會將上限約束 <3.0.0 重新解釋為 <4.0.0

yaml
environment:
  sdk: '>=2.14.0 <3.0.0'           # This is interpreted as '>=2.14.0 <4.0.0'

這允許開發人員將 Dart 3 健全的空值安全性與已經支援 2.12 空值安全性的套件一起使用,而無需進行第二次遷移,除非程式碼受到任何其他 Dart 3 變更的影響。

測試影響

#

若要了解您的原始碼是否受到任何 Dart 3 變更的影響,請使用以下步驟

$ dart --version    # Make sure this reports 3.0.0 or higher.
$ dart pub get      # This should resolve without issues.
$ dart analyze      # This should pass without errors.

如果 pub get 步驟失敗,請嘗試升級您的相依性,以查看較新版本是否可能支援 Dart 3

$ dart pub upgrade
$ dart analyze      # This should pass without errors.

或者,如果需要,也請包含主要版本升級

$ dart pub upgrade --major-versions
$ dart analyze      # This should pass without errors.

Dart 3 語言變更

#

100% 健全的空值安全

#

Dart 2.12 在兩年多前引入了空值安全性。在 Dart 2.12 中,使用者需要使用 pubspec 設定啟用空值安全性。在 Dart 3 中,空值安全性是內建的;您無法關閉它。

範圍

#

這是一個未版本化變更,適用於所有 Dart 3 程式碼。

徵兆

#

在沒有空值安全性支援的情況下開發的套件,在解析具有 pub get 的相依性時會導致問題

$ dart pub get

Because pkg1 doesn't support null safety, version solving failed.
The lower bound of "sdk: '>=2.9.0 <3.0.0'" must be 2.12.0 or higher to enable null safety.

使用語言版本註解選擇低於 2.12 的任何語言版本來選擇退出空值安全性的函式庫,將導致分析或編譯錯誤

$ dart analyze .
Analyzing ....                         0.6s

  error • lib/pkg1.dart:1:1 • The language version must be >=2.12.0. 
  Try removing the language version override and migrating the code.
  • illegal_language_version_override
$ dart run bin/my_app.dart
../pkg1/lib/pkg1.dart:1:1: Error: Library doesn't support null safety.
// @dart=2.9
^^^^^^^^^^^^

遷移

#

在開始任何遷移到 Dart 3 之前,請確保您的應用程式或套件已 100% 遷移以啟用空值安全性。這需要 Dart 2.19 SDK,而不是 Dart 3 SDK。若要了解如何先將您的應用程式或套件遷移以支援空值安全性,請查看空值安全遷移指南

預設值的冒號語法

#

基於歷史原因,具名選用參數可以使用 := 指定其預設值。在 Dart 3 中,僅允許使用 = 語法。

範圍

#

這是一個版本化變更,僅適用於語言版本 3.0 或更高版本。

徵兆

#

Dart 分析產生類似以下的錯誤

line 2 • Using a colon as a separator before a default value is no longer supported.

遷移

#

從使用冒號變更

dart
int someInt({int x: 0}) => x;

變更為使用等號

dart
int someInt({int x = 0}) => x;

此遷移可以手動完成,也可以使用 dart fix 自動化

$ dart fix --apply --code=obsolete_colon_for_default_value

mixin

#

在 Dart 3 之前,任何 class 都可以用作 mixin,只要它沒有宣告的建構子且沒有除了 Object 之外的超類別。

在 Dart 3 中,在語言版本 3.0 或更高版本的函式庫中宣告的類別不能用作 mixin,除非標記為 mixin。此限制適用於嘗試將類別用作 mixin 的任何函式庫中的程式碼,無論後者函式庫的語言版本為何。

範圍

#

這是一個版本化變更,僅適用於語言版本 3.0 或更高版本。

徵兆

#

類似以下的分析錯誤

Mixin can only be applied to class.

當在 with 子句中使用既不是 mixin class 也不是 mixin 的類別時,分析器會產生此診斷訊息。

遷移

#

判斷類別是否旨在用作 mixin。

如果類別定義了介面,請考慮使用 implements

switch

#

Dart 3.0 將 switch case 解釋為模式而不是常數運算式。

範圍

#

這是一個版本化變更,僅適用於語言版本 3.0 或更高版本。

徵兆

#

在 switch case 中找到的大多數常數運算式都是有效的模式,具有相同的含義 (具名常數、常值等)。這些行為將相同,並且不會出現任何徵兆。

少數不是有效模式的常數運算式將觸發invalid_case_patterns lint

遷移

#

您可以透過在 case 模式前面加上 const 來還原為原始行為,使其不再被解釋為模式

dart
case const [1, 2]:
case const {'k': 'v'}:
case const {1, 2}:
case const Point(1, 2):

您可以透過使用 dart fix 或從您的 IDE 執行此破壞性變更的快速修復。

continue

#

如果 continue 語句的目標標籤不是迴圈 (fordowhile 語句) 或 switch 成員,Dart 3 會報告編譯時期錯誤。

範圍

#

這是一個版本化變更,僅適用於語言版本 3.0 或更高版本。

徵兆

#

您將看到類似以下的錯誤

The label used in a 'continue' statement must be defined on either a loop or a switch member.

遷移

#

如果變更行為是可以接受的,請變更 continue 以目標有效的標籤語句,該語句必須附加到 fordowhile 語句。

如果您想保留行為,請將 continue 語句變更為 break 語句。在 Dart 的先前版本中,未針對迴圈或 switch 成員的 continue 語句的行為類似於 break

Dart 3 核心函式庫變更

#

已移除的 API

#

破壞性變更 #49529:核心函式庫已清理以移除已棄用多年的 API。以下 API 在 Dart 核心函式庫中不再存在。

範圍

#

這是一個未版本化變更,適用於所有 Dart 3 程式碼。

dart:core

#
  • 移除了已棄用的 List 建構子,因為它不是空值安全的。請使用清單常值 (例如,空清單使用 [],或空類型清單使用 <int>[]) 或 List.filled。這僅影響非空值安全程式碼,因為空值安全程式碼已經無法使用此建構子。
  • 移除了 int.parsedouble.parsenum.parse 上已棄用的 onError 引數。請改用 tryParse 方法。
  • 移除了已棄用的 proxyProvisional 註解。原始的 proxy 註解在 Dart 2 中沒有任何作用,而 Provisional 類型和 provisional 常數僅在 Dart 2.0 開發過程中內部使用。
  • 移除了已棄用的 Deprecated.expires getter。請改用 Deprecated.message
  • 移除了已棄用的 CastError 錯誤。請改用 TypeError
  • 移除了已棄用的 FallThroughError 錯誤。先前拋出此錯誤的 fall-through 種類在 Dart 2.0 中已成為編譯時期錯誤。
  • 移除了已棄用的 NullThrownError 錯誤。此錯誤永遠不會從空值安全程式碼中拋出。
  • 移除了已棄用的 AbstractClassInstantiationError 錯誤。在 Dart 2.0 中,呼叫抽象類別的建構子已成為編譯時期錯誤。
  • 移除了已棄用的 CyclicInitializationError。在空值安全程式碼中,不再在執行時期偵測到循環相依性。此類程式碼將改以其他方式失敗,可能會出現 StackOverflowError。
  • 移除了已棄用的 NoSuchMethodError 預設建構子。請改用 NoSuchMethodError.withInvocation 具名建構子。
  • 移除了已棄用的 BidirectionalIterator 類別。現有的雙向迭代器仍然可以運作,它們只是沒有共用的超類型將它們鎖定為用於向後移動的特定名稱。

dart:async

#

dart:developer

#

dart:html

#
  • 如先前宣布,已移除 DocumentHtmlDocument 中已棄用的 registerElementregisterElement2 方法。請參閱 #49536 了解詳情。

dart:math

#
  • Random 介面只能實作,不能擴充。

dart:io

#
  • 更新 NetworkProfiling 以容納在 vm_service:11.0.0 中引入的新 String ID

徵兆

#

Dart 分析 (例如,在您的 IDE 中,或在 dart analyze/flutter analyze 中) 將失敗並出現類似以下的錯誤

error line 2 • Undefined class 'CyclicInitializationError'.

遷移

#

手動遷移以避免使用這些 API。

Extends 與 implements

#

Dart 3 支援新的類別修飾詞,這些修飾詞可以限制類別的功能。它們已應用於核心函式庫中的許多類別。

範圍

#

這是一個版本化變更,僅適用於語言版本 3.0 或更高版本。

dart:async

#
  • 以下宣告只能實作,不能擴充

    • StreamConsumer
    • StreamIterator
    • StreamTransformer
    • MultiStreamController

    這些宣告都不包含任何要繼承的實作。它們被標記為 interface 以表示它們僅用作介面。

dart:core

#
  • Function 類型不再能被實作、擴充或混入。自 Dart 2.0 以來,為了向後相容性,允許編寫 implements Function,但它沒有任何效果。在 Dart 3.0 中,Function 類型是 final 且無法子類型化,從而防止程式碼錯誤地假設它可以運作。

  • 以下宣告只能實作,不能擴充

    • Comparable
    • Exception
    • Iterator
    • Pattern
    • Match
    • RegExp
    • RegExpMatch
    • StackTrace
    • StringSink

    這些宣告都不包含任何要繼承的實作。它們被標記為 interface 以表示它們僅用作介面。

  • 以下宣告不再能被實作或擴充

    • MapEntry
    • OutOfMemoryError
    • StackOverflowError
    • Expando
    • WeakReference
    • Finalizer

    MapEntry 值類別受到限制,以啟用後續的最佳化。其餘類別與平台緊密耦合,不打算被子類別化或實作。

dart:collection

#
  • 以下介面不再能被擴充,只能實作

    • Queue
  • 以下實作類別不再能被實作

    • LinkedList
    • LinkedListEntry
  • 以下實作類別不再能被實作或擴充

    • HasNextIterator (也已棄用。)
    • HashMap
    • LinkedHashMap
    • HashSet
    • LinkedHashSet
    • DoubleLinkedQueue
    • ListQueue
    • SplayTreeMap
    • SplayTreeSet

Dart 3 工具變更

#

已移除的工具

#

從歷史上看,Dart 團隊提供了許多較小的開發人員工具,用於格式化程式碼 (dartfmt)、分析程式碼 (dartanalyzer) 等。在 Dart 2.10 (2020 年 10 月),我們推出了一個新的統一 Dart 開發人員工具,即dart 工具

範圍

#

這是一個未版本化變更,適用於所有 Dart 3 程式碼。

徵兆

#

在 Dart 3 中,這些較小的工具不存在,並且已被新的組合 dart 工具取代。

遷移

#

使用 dart 工具中提供的新子命令

歷史工具dart 替代工具棄用停止使用
stagehanddart create2.142.14*
dartfmtdart format2.142.15
dart2nativedart compile exe2.142.15
dart2jsdart compile js2.172.18
dartdevcwebdev2.172.18
dartanalyzerdart analyze2.162.18
dartdocdart doc2.162.17
pubdart pub2.152.17

空值安全遷移工具

#

以下空值安全遷移命令已被移除,因為 Dart 3 不支援沒有空值安全的程式碼

  • dart migrate
  • dart pub upgrade --null-safety
  • dart pub outdated --mode=null-safety

範圍

#

這是一個未版本化變更,適用於所有 Dart 3 程式碼。

徵兆

#

這些命令將失敗。

遷移

#

使用 Dart 2.19 遷移到空值安全

分析器設定

#

用於啟用更嚴格檢查的分析器設定選項已變更。

範圍

#

這是一個未版本化變更,適用於所有 Dart 3 程式碼。

徵兆

#

先前的設定選項將失敗並顯示類似以下的警告

The option 'implicit-casts' is no longer supported.
Try using the new 'strict-casts' option.

遷移

#

取代分析器設定的這一部分

yaml
analyzer:
  strong-mode:
    implicit-casts: false
    implicit-dynamic: false

使用

yaml
analyzer:
  language:
    strict-casts: true
    strict-raw-types: true

其他工具變更

#
  • 已棄用的 Observatory 預設為隱藏。我們建議使用 DevTools
  • 命令 dart format fix 已被 dart fix 取代 #1153
  • SDK 中針對 Dart Web 編譯器捆綁的快照檔案已清理 #50700
  • dart format 的輸出針對 某些程式碼 略有變更。
  • 結束對 Windows 上舊 pub-cache 位置的向後相容性。在 Dart 3 之前,%APPDATA%\Pub\Cache 是 pub-cache 的備用位置。從 Dart 3 開始,預設的 pub-cache 位於 %LOCALAPPDATA%\Pub\Cache。如果您已將全域啟用的套件新增至您的 PATH,請考慮更新 PATH 以包含 %LOCALAPPDATA%\Pub\Cache\bin

範圍

#

這是一個未版本化變更,適用於所有 Dart 3 程式碼。