Dart 2.17 正式發布
文/ Michael Thomsen, Google Dart 團隊產品經理,2022 年 5 月 12 日發表于 Dart 官方博客
隨著 Flutter 3 在本次 I/O 大會的發布,我們也同時正式發布了 Dart 2.17 穩定版 SDK。這個版本的發布是圍繞著我們的核心主題構建的,即:領先的生產力和平臺可移植性。
Dart 2.17 提供了新的語言特性:枚舉支持成員變量、改進的超類參數繼承,以及更為靈活的命名參數。我們同時為 package:lints 開啟了 2.x 版本,這是一套官方的 lint 規則,是根據我們總結的 Dart 最佳實踐整合而成的一個 lint 規則集。與此同時,我們也更新了核心庫的 API 文檔,為其帶來了豐富的示例代碼。并且,為了改善平臺集成特性,我們在 Flutter 插件中提供了一個新的模版,使用 dart:ffi 與原生平臺進行 C 語言的互操作、對 RISC-V 指令集提供實驗性支持,以及對 macOS 和 Windows 可執行文件的簽名支持。

編程語言新特性助力生產力提升
我們一直在持續地改進 Dart 編程語言,不斷添加新特性以及改進現有的特性,以助力開發者們工作效率的提升。Dart 2.17 增加了對枚舉成員變量的支持,優化了在構造函數中使用命名參數的方式,并且開始使用繼承超類的參數以減少冗長和重復的代碼。
增強的支持成員變量的枚舉
枚舉非常適合表示一組離散的狀態。例如,我們可以將水描述為 enum Water { frozen, lukewarm, boiling }。但如果我們想在 enum 上添加一些方法,例如,將每個狀態轉換為溫度,并支持將 enum 轉換為 String,該怎么辦?或許我們可以使用擴展方法來添加一個 waterToTemp() 方法,但我們必須時刻注意它與 enum 的同步。對于 String 我們希望覆寫 toString() 方法,但它不支持這么做。
在 Dart 2.17 中現已支持枚舉類型的成員變量。這意味著我們可以添加保存狀態的字段、設置狀態的構造函數、具有功能的方法,甚至覆寫現有的方法。社區中許多開發者一直有這樣的需求,這是我們在 Dart 編程語言倉庫的問題追蹤中 投票排名第三的問題。
繼續拿 Water 舉例,我們可以添加一個保存溫度的 int 字段,并添加接收 int 的默認構造函數:
enum Water
const Water(this.tempInFahrenheit);
final int tempInFahrenheit;
}
為了確保在創建枚舉時構造函數被正常調用,我們需要為每一個枚舉值附以顯式的調用:
enum Water {
frozen(32),
lukewarm(100),
boiling(212);
}
想要支持從枚舉轉換為 String,我們可以很簡單地覆寫 toString 方法,因為 enums 也繼承自 Object:
@override
String toString() => "The $name water is $tempInFahrenheit F.";
如此一來,你就有了一個可以輕松實例化完整功能的枚舉類,并且可以在任意位置調用方法:
void main() {
print(Water.frozen); // 打印內容為 “The frozen water is 32 F.”
}
這兩種方法的完整示例如下所示,有了這些改動,新版本的代碼更易于閱讀和維護。

超類的初始化構造
當你的代碼存在類型繼承關系時,一個常見的做法是將一些構造函數參數傳遞給超類的構造函數。為此子類需要 1) 在其構造函數中列出每個參數 2) 使用這些參數調用超類的構造函數。這導致了大量的代碼重復,使代碼難以閱讀和維護。
幾位 Dart 社區成員幫助 Dart 實現了這項語言目標。半年前,GitHub 用戶 @roy-sianez 提交了一個 語言問題。他的建議類似于 GitHub 用戶 @apps-transround 先前的 建議:也許我們可以通過引入一個新的方式來表示在超類中指定了一個參數,來解決這個問題。我們認為這是一個好主意,因此已將其實現并添加到了 Dart 2.17 版本中。從以下示例中可以看出,這與 Flutter widget 的代碼有很強的相關性。實際上當我們將這項特性應用到 Flutter 框架時,我們看到框架總共減少了 近兩千行代碼!

可在任意參數位置使用命名參數
最后,我們改進了方法調用時命名參數的方式。在此次更新之前,命名參數的調用必須出現在普通參數列表的后面。當你想要提升代碼可讀性,希望將命名參數寫在靠前的位置但它無法工作時,會覺得非常惆悵。例如下方 List<T>.generate 構造函數的調用。此次更新之前 growable 參數必須放在最后,這會導致這個參數很容易被可能有很多內容的構造參數所影響而錯過。現在你可以根據自己的喜好對它們進行排序,你可以先使用命名參數,最后使用生成器參數。

更多有關這三項改進的示例,請參閱我們更新的 枚舉、超類的初始化構造 和 命名參數 示例代碼。
生產力工具改進
回到生產力的主題,我們圍繞生產力對核心工具進行了一些改進。
在 Dart 2.14 中,我們引入了 package:lints,它與 Dart 分析器一起工作以防止你編寫錯誤的代碼,并使用更規范的規則審查你的 Dart 代碼。之后分析器中又新增了許多代碼提示規則,我們對其進行了仔細分類,并從中選擇了 10 條新的用于所有 Dart 代碼的代碼提示規則 ,以及 2 條新的專門用于 Flutter 代碼的代碼提示規則。它們包括確保你導入的 package 中有正確地在你 pubspec 文件中聲明、防止濫用對類型參數的空檢查以及確保子屬性格式一致的代碼提示規則。你可以簡單地使用命令升級到新的 lints package:
- 對 Dart package 可以使用:
dart pub upgrade —-major-versions lints - 對 Flutter package 可以使用:
flutter pub upgrade —-major-versions flutter_lints
SecureSockets 通常用于啟用使用 TLS 和 SSL 保護的 TCP 套接字連接。在 Dart 2.17 之前,因為沒有辦法檢查安全數據流量,在開發過程中調試這些加密連接變得十分棘手。現在我們添加了對指定 keyLog 文件的支持,指定后,當與服務器交換新的 TLS 密鑰時,NSS 密鑰日志格式 中的一行文本將附加到文件中。這將使網絡流量分析工具 (例如 Wireshark) 能夠解密通過套接字發送的內容。更多詳細信息,請參閱SecureSocket.connect() 的 API 文檔。
dart doc 生成的 API 文檔是大多數 Dart 開發者學習新 API 的重要內容之一。雖然我們的核心庫 API長期以來都有豐富的文本描述,但許多開發者告訴我們,他們更喜歡通過閱讀示例代碼來學習 API。在 Dart 2.17 中,我們檢查了所有主要的核心庫,為瀏覽量排名的前 200 個頁面添加了詳實的示例代碼。你可以對比 dart:convert 在 Dart 2.16 和 2.17 的文檔頁面查看這些改變,希望這些改變可以幫助你更好地使用 API 文檔。
助力生產力的提高不僅是做加法,做減法也同樣重要,我們清理了一些堆積的內容,并刪除了 SDK 里已棄用的的 API,這將幫助我們保持更小的代碼體積,這對新上手的開發者們尤為重要。為此,我們從 dart:io 庫中刪除了 231 行已棄用的代碼。如果你仍在使用這些已棄用的 API,你可以使用 dart fix 進行修復和替換。我們還在繼續努力刪除 已棄用的 Dart CLI 工具,本次更新刪除了 dartdoc 工具 (使用dart doc 代替) 和 pub 工具 (使用 dart pub 或 flutter pub 代替)。
擴大平臺集成和支持
第二個核心主題是平臺集成和支持。Dart 是一種真正的多平臺語言。雖然我們已經支持 大量的平臺,但我們仍在不斷拓展新平臺,以確保你可以與每個受支持的平臺深度集成,同時也關注更新興的平臺。
我們 與 C 語言或原生代碼互操作 的核心機制——Dart FFI,是一種將 Dart 代碼與現有原生平臺代碼集成的流行方式。在 Flutter 上,FFI 是構建使用宿主平臺原生 API (例如 Windows win32 API) 插件的好方法。在 Dart 2.17 和 Flutter 3 中,我們向 flutter 工具添加了 FFI 的模板,現在你可以輕松地創建 FFI 插件,這些插件具有通過 dart:ffi 調用原生代碼支持的 Dart API。詳細信息請參閱開發者文檔 開發 package 和插件 頁面。
FFI 現在支持特定于 ABI 的類型,可以在具有特定 ABI (應用程序二進制接口) 類型的平臺上使用 FFI。例如,現在你可以使用 Long (C 語言中的 long) 正確表示具有特定于 ABI 大小的長整數,由于 CPU 架構的區別,結果可能是 32 位或 64 位。有關支持類型的完整列表,請參閱 AbiSpecificInteger API 頁面 中的 "Implementers" 列表。
在使用 Dart FFI 與原生平臺深度集成時,有時需要將 Dart 分配的內存或其他資源 (端口、文件等) 的清理行為與原生代碼對齊。長期以來,這個問題都十分棘手,因為 Dart 是一種會自動處理垃圾回收清理行為的語言。在 Dart 2.17 中,我們通過引入 Finalizer 的概念解決了這個問題,它包括一個 Finalizable 標記接口,用于「標記」不應過早終結或丟棄的對象,以及一個 NativeFinalizer 可以附加到 Dart 對象上,當對象即將被垃圾回收時提供回調運行。Finalizer 讓原生代碼和 Dart 代碼中同時運行清理。更多詳細信息請參閱 NativeFinalizer API 文檔 中的描述和示例,或 WeakReferences 以及 Finalizer 在 Dart 代碼中的類似支持。
將 Dart 編譯為本機代碼的支持,也是使 Flutter 應用具有出色的啟動性能和快速渲染的核心。除此之外,你還可以使用 dart compile 編譯 Dart 文件為可執行文件。這些可執行文件可以在任何機器上獨立運行,無需安裝 Dart SDK。Dart 2.17 中的另一個新功能是支持對可執行文件進行簽名,生成的產物可以在經常需要簽名的 Windows 和 macOS 上進行部署。
我們還保持在新興的平臺前沿,繼續擴大我們所支持的平臺集。RISC-V 是一個全新的指令集體系。RISC-V International 是一家全球性的非盈利組織,擁有 RISC-V 規范,使得指令集自由開放。這仍然是一個新興的平臺,但我們對其潛力感到興奮,因此我們的 2.17.0–266.1.beta Linux 版本包含了對它的實驗性支持。我們希望能夠聽到你的反饋,你可以 提出問題 或 分享 你的體驗!
開始使用 Dart 2.17!
我們希望 Dart 的 2.17 正式版能打動你并能助力你提高工作效率,也同時能夠把你的應用帶去更多的平臺。即刻下載 Dart 2.17 并開始使用,也安裝使用 Flutter 3,使用內置的 Dart SDK。
原文鏈接:
https://medium.com/dartlang/dart-2-17-b216bfc80c5d
本地化: CFUG 團隊
浙公網安備 33010602011771號