(譯)Dart 2.13 類型別名、改進FFI、優(yōu)化性能、Docker鏡像支持

今天,我們宣布Dart 2.13具有類型別名,這是目前我們要求排名第二的語言功能。Dart 2.13還包括改進的Dart FFI和更好的性能,并且我們?yōu)镈art提供了新的Docker Official Images。這篇文章提供了2.12中引入的null安全功能的更新,討論了2.13的新功能,有關(guān)DockerGoogle Cloud對Dart后端的支持的一些令人振奮的消息,并預(yù)覽了您可能期望在未來版本中看到的一些更改。

空安全更新

我們在3月的Dart 2.12版本中啟動了聲音無效安全性。空安全性是Dart最新的主要生產(chǎn)力功能,旨在幫助您避免空錯誤-一類通常很難發(fā)現(xiàn)的錯誤。通過該發(fā)布,我們鼓勵軟件包發(fā)布者開始將pub.dev上的共享軟件包遷移到安全性為空。
我們非常高興地看到采用null安全性的速度有多快!發(fā)布后僅幾個月,pub.dev上最流行的500個軟件包中有93%已經(jīng)支持null安全。我們衷心感謝所有軟件包開發(fā)人員這么快地完成這項工作,并幫助整個生態(tài)系統(tǒng)向前發(fā)展!
有如此多的支持null安全的軟件包,您很有可能開始遷移應(yīng)用程序以使用null安全。第一步是用來dart pub outdated檢查您的應(yīng)用程序的依賴關(guān)系。有關(guān)詳細信息,請參見《空安全遷移指南》。我們還更改了dart createflutter create模板,以便現(xiàn)在默認情況下在新應(yīng)用和程序包中啟用null安全。

類型別名

類型別名是2.13語言的一項新功能。它擴展了我們先前的支持,該支持允許創(chuàng)建函數(shù)類型的類型別名,但不能創(chuàng)建任何其他類型。這個備受追捧的功能是語言問題跟蹤器中評分排名第二的功能。
使用類型別名,可以為任何現(xiàn)有類型創(chuàng)建一個新名稱,然后可以在可以使用原始類型的任何地方使用該名稱。您實際上并沒有定義新的類型,只是引入了簡寫別名。別名甚至通過類型相等性測試:

typedef Integer = int;
void main() {
  print(int == Integer); // true
}

那么,您可以將類型別名用于什么呢?一種常見的用法是為一種類型賦予一個簡短或更具描述性的名稱,從而使您的代碼更具可讀性和可維護性。
一個很好的示例是使用JSON。在這里,我們可以定義一個新的類型別名Json,該別名將JSON文檔描述為從String鍵到任何值(使用該dynamic類型)的映射。然后,Json當定義fromJson命名構(gòu)造函數(shù)和jsongetter時,可以使用該類型別名

typedef Json = Map<String, dynamic>;
class User {
  final String name;
  final int age;
  User.fromJson(Json json) :
    name = json['name'],
    age = json['age'];
Json get json => {
    'name': name,
    'age': age,
  };
}

您還可以在命名類的類型別名上調(diào)用構(gòu)造函數(shù),因此以下內(nèi)容完全合法:

main(){ 
  var j = Json(); 
  j ['name'] ='Michael'; 
}

通過使用類型別名為復(fù)雜類型命名,可以使讀者更容易理解代碼的不變式。例如,以下代碼定義類型別名,以描述包含通用類型的鍵和typeX值的映射List<X>。通過為類型賦予一個帶有單個類型參數(shù)的名稱,映射的規(guī)則結(jié)構(gòu)對代碼閱讀者來說變得更加明顯。

typedef MapToList<X> = Map<X, List<X>>;
void main() {
  MapToList<int> m = {};
  m[7] = [7]; // OK
  m[8] = [2, 2, 2]; // OK
  for (var x in m.keys) {
    print('$x --> ${m[x]}');
  }
}
=>
7 --> [7]
8 --> [2, 2, 2]

如果嘗試使用不匹配的類型,則會收到分析錯誤:

m[42] = ['The', 'meaning', 'of', 'life'];
=>
The element type 'String' can't be assigned to the list type 'int'.

重命名公共庫中的類時,甚至可以使用類型別名。想象一下PoorlyNamedClass,您想將公共庫中現(xiàn)有的類重命名為BetterNamedClass。如果僅重命名該類,則您的API客戶將突然獲得編譯錯誤。使用類型別名,您可以繼續(xù)進行重命名,但是可以為舊的類名稱定義一個新的類型別名,然后@Deprecated為該舊名稱添加注釋。使用時,PoorlyNamedClass會在使用時引起警告,但仍會像以前一樣繼續(xù)編譯和工作,使用戶有時間升級其代碼。
以下是實現(xiàn)BetterNamedClass和棄用的方式PoorlyNamedClass(在名為的文件中mylibrary.dart):

class BetterNamedClass {...}
@Deprecated('Use BetterNamedClass instead')
typedef PoorlyNamedClass = BetterNamedClass;

這就是某人嘗試使用的內(nèi)容PoorlyNamedClass

import 'mylibrary.dart';
void main() {
  PoorlyNamedClass p;
}
=>
'PoorlyNamedClass' is deprecated and shouldn't be used. Use BetterNamedClass instead.

從Dart 2.13開始,可以使用類型別名功能。要啟用它,請將pubspec.yaml中較低的Dart SDK約束設(shè)置為至少2.13

environment:
  sdk: ">=2.13.0 <3.0.0"

由于語言版本控制,此功能向后兼容。即使在2.13之前的程序包無法定義自己的類型別名,在2.13下具有較低SDK約束的程序包也可以安全地引用2.13程序包中定義的類型別名。

Dart 2.13 FFI變更

在Dart FFI中,我們還有一些新功能,這是我們用于調(diào)用C代碼的互操作機制。
首先,F(xiàn)FI現(xiàn)在支持具有內(nèi)聯(lián)數(shù)組的結(jié)構(gòu)。考慮一個具有內(nèi)聯(lián)數(shù)組的C結(jié)構(gòu),如下所示:

struct MyStruct { 
  uint8_t arr [8]; 
}

現(xiàn)在,您可以將其直接包裝在Dart中,并使用類型參數(shù)指定元素類型Array

class StructInlineArray extends Struct {
  @Array(8)
  external Array<Uint8> arr;
}

其次,F(xiàn)FI現(xiàn)在支持打包結(jié)構(gòu)。通常,將結(jié)構(gòu)布置在內(nèi)存中,以便成員位于地址邊界內(nèi),以便于CPU訪問。對于打包的結(jié)構(gòu),通常以特定于平臺的方式省略了某些填充以降低總體內(nèi)存消耗。使用新的@Packed(<alignment>)注釋,您可以輕松指定填充。例如,以下代碼創(chuàng)建一個在內(nèi)存中具有4字節(jié)對齊的結(jié)構(gòu):

@Packed(4)
class TASKDIALOGCONFIG extends Struct {
  @Uint32()
  external int cbSize;
  @IntPtr()
  external int hwndParent;
  @IntPtr()
  external int hInstance;
  @Uint32()
  external int dwFlags;
  ...
}

Dart 2.13的性能變化

我們正在繼續(xù)努力減少Dart代碼的應(yīng)用程序大小和內(nèi)存占用。在大型Flutter應(yīng)用程序中,表示AOT編譯的Dart程序的元數(shù)據(jù)的內(nèi)部結(jié)構(gòu)可能會占用相當大的內(nèi)存。提供這些元數(shù)據(jù)的大部分是為了啟用諸如熱重裝,交互式調(diào)試以及人類可讀堆棧跟蹤的格式設(shè)置之類的功能,這些功能在已部署的應(yīng)用程序中從未使用過。在過去的一年中,我們一直在重組Dart本機運行時,以消除盡可能多的此類開銷。其中一些改進適用于所有以發(fā)行模式構(gòu)建的Flutter應(yīng)用程序,但有些改進要求您通過使用--split-debug-info標志將調(diào)試信息從AOT編譯的應(yīng)用程序中分離出來,從而放棄人類可讀的堆棧跟蹤。

Dart 2.13包含許多更改,這些更改大大減少了--split-debug-info使用時程序元數(shù)據(jù)所占用的空間。以Flutter Gallery應(yīng)用程序為例。在Android上,發(fā)布的APK包含調(diào)試信息為112.4 MB,不包含調(diào)試信息為106.7 MB(減少了5%)。這個APK包含很多資產(chǎn)。僅查看APK中的代碼元數(shù)據(jù),它從Dart 2.12中的5.7MB減少到Dart 2.13中的3.7MB(減少了35%)

如果應(yīng)用程序大小和內(nèi)存占用對您很重要,請考慮使用該--split-debug-info標志省略調(diào)試信息。請注意,這樣做時,您將需要使用symbolize命令使堆棧跟蹤再次可被人類讀取。

官方Docker支持和Google Cloud上的Dart

Dart現(xiàn)在可作為Docker Official Images使用。盡管Dart提供了Docker映像已有多年,但這些新的Dart映像已由Docker進行了測試和驗證,以遵循最佳實踐。它們還支持提前(AOT)編譯,這可以大大減少已構(gòu)建容器的大小,并可以提高在容器環(huán)境(如Cloud Run)中的部署速度。
盡管Dart一直致力于使諸如Flutter之類的應(yīng)用程序框架能夠在每個屏幕上驅(qū)動漂亮的像素,但我們意識到,大多數(shù)用戶體驗背后都是至少一項托管服務(wù)。通過使用Dart輕松構(gòu)建后端服務(wù),我們支持完整的堆棧體驗,使開發(fā)人員可以使用與為前端小部件提供支持的語言和業(yè)務(wù)邏輯相同的語言和業(yè)務(wù)邏輯,將其應(yīng)用程序擴展到云中。

通常,將Dart用于Flutter應(yīng)用程序后端特別適合Google托管的無服務(wù)器平臺Cloud Run的簡單性和可伸縮性。這包括從零到零的比例,這意味著當后端不處理任何請求時,您不會招致費用。我們與Google Cloud團隊合作,為Dart提供了Functions Framework,這是一組軟件包,工具和示例,可以輕松編寫Dart函數(shù)來部署,而不是使用完整的服務(wù)器來處理HTTP請求和CloudEvent
查看我們的Google Cloud文檔以開始使用。

后續(xù)計劃

我們已經(jīng)在為即將發(fā)布的版本進行一些激動人心的更改。與往常一樣,您可以使用language funnel來關(guān)注我們的進度。

我們正在研究的一個領(lǐng)域是針對Dart和Flutter的一組新的規(guī)范。lints是配置Dart靜態(tài)分析的強大方法,但是由于有數(shù)百種可能的lints可以打開或關(guān)閉,因此很難決定要選擇什么。我們目前正在定義兩個標準的lints集,默認情況下,我們將在Dart和Flutter項目中應(yīng)用這些lints集。我們希望在下一個穩(wěn)定版本中默認啟用此功能。如果需要預(yù)覽,請簽出lintsflutter_lints這兩個包。
最后,如果您要深度嵌入Dart VM運行時,請注意,我們打算為此棄用現(xiàn)有機制。我們將用基于Dart FFI的更快,更靈活的模型替換它。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容