今天,我們宣布Dart 2.13具有類型別名
,這是目前我們要求排名第二的語言功能。Dart 2.13還包括改進的Dart FFI
和更好的性能,并且我們?yōu)镈art提供了新的Docker Official Images
。這篇文章提供了2.12中引入的null
安全功能的更新,討論了2.13的新功能,有關(guān)Docker
和Google 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 create
和flutter 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ù)雜類型命名,可以使讀者更容易理解代碼的不變式。例如,以下代碼定義類型別名,以描述包含通用類型的鍵和type
的X
值的映射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ù)覽,請簽出lints
和flutter_lints
這兩個包。
最后,如果您要深度嵌入Dart VM運行時,請注意,我們打算為此棄用現(xiàn)有機制。我們將用基于Dart FFI
的更快,更靈活的模型替換它。