1.Dart平臺獨有的功能
在我們詳細研究可靠的空安全和FFI之前,讓我們討論一下Dart平臺如何將它們適合我們的目標昆淡。編程語言傾向于共享許多的功能锰瘸。例如,許多語言都支持面向?qū)ο蟮木幊袒蛘呖梢栽赪eb上運行昂灵。真正使語言與眾不同的是它們獨特的功能組合
Dart的獨特功能涵蓋了三個方面:
可移植性:高效的編譯器為設(shè)備生成
x86
和ARM
機器代碼避凝,并為Web生成優(yōu)化的JavaScript。一個廣泛的目標是支持:移動設(shè)備眨补,臺式機管削,應(yīng)用后端,等等撑螺。大量的庫和軟件包提供了可在所有平臺上使用的一致的API含思,從而進一步降低了創(chuàng)建真正的多平臺應(yīng)用程序的成本。高效:Dart平臺支持熱重裝甘晤,從而可以對本機設(shè)備和Web進行快速含潘,迭代的開發(fā)。Dart提供了諸如內(nèi)存隔離線程和異步/等待之類的豐富結(jié)構(gòu)线婚,用于處理常見的并發(fā)和事件驅(qū)動的應(yīng)用程序模式遏弱。
健壯:Dart健全的,空安全類型系統(tǒng)會在開發(fā)過程中捕獲錯誤酌伊。整個平臺具有高度的可擴展性和可靠性腾窝,其廣泛的應(yīng)用程序用于生產(chǎn)已超過十年,包括
Google Ads
和Google Assistant
等業(yè)務(wù)關(guān)鍵型應(yīng)用程序居砖。
可靠的空安全性使類型系統(tǒng)更加強大虹脯,并實現(xiàn)了更好的性能。Dart FFI使您可以使用現(xiàn)有的C庫以實現(xiàn)更好的可移植性奏候,并可以選擇對性能要求很高的任務(wù)使用經(jīng)過高度調(diào)整的C代碼循集。
2.可靠的空安全
自Dart 2.0引入可靠的空安全類型系統(tǒng)以來,空安全是Dart語言的最大補充蔗草≈渫空安全性進一步增強了類型系統(tǒng),使您能夠捕獲空錯誤咒精,這是應(yīng)用程序崩潰的常見原因镶柱。通過選擇空安全性,您可以在開發(fā)過程中捕獲空錯誤模叙,從而防止生產(chǎn)崩潰歇拆。
合理的空安全性是圍繞一些核心原則設(shè)計的。讓我們重新審視這些原則如何影響您作為開發(fā)人員。
3.默認情況下可為空:是對類型系統(tǒng)的基本的改變
空安全之前的核心挑戰(zhàn)是故觅,您無法分辨預期傳遞空值的代碼與不能使用空值的代碼之間的區(qū)別厂庇。幾個月前,我們在Flutter主渠道渠道中發(fā)現(xiàn)了一個錯誤输吏,該錯誤會在某些機器配置上使各種flutter工具命令崩潰权旷,并出現(xiàn)null
錯誤:The method '>=' was called on null
。根本的問題是這樣的代碼:
final int major = version?.major;
final int minor = version?.minor;
if (globals.platform.isMacOS) {
// plugin path of Android Studio changed after version 4.1.
if (major >= 4 && minor >= 1) {
...
您能發(fā)現(xiàn)錯誤嗎贯溅?因為version
可以為null
拄氯,所以major
和minor
也可以為null
。似乎很容易孤立地發(fā)現(xiàn)此錯誤盗迟,但實際上坤邪,即使是經(jīng)過嚴格的代碼審查過程(如Flutter主分支中所用的代碼),這種代碼也會無時無刻不在出現(xiàn)罚缕。出于安全考慮艇纺,靜態(tài)分析會立即捕獲此問題。(可以在DartPad中試用邮弹。)
那是一個非常簡單的錯誤黔衡。在Google內(nèi)部內(nèi)部在代碼中早期使用null安全性的過程中,我們發(fā)現(xiàn)了很多復雜的錯誤腌乡。其中一些是已經(jīng)存在多年的bug盟劫,但是如果沒有null安全性的額外靜態(tài)檢查,團隊就無法找到原因与纽。這里有一些例子:
- 一個內(nèi)部團隊發(fā)現(xiàn)侣签,他們經(jīng)常檢查永遠不能為
null
的表達式的null
值。使用protobuf
的代碼中最經(jīng)常出現(xiàn)此問題急迂,其中可選字段在未設(shè)置時返回默認值影所,并且永遠不會為null。如此一來僚碎,通過混淆默認值和空值猴娩,代碼錯誤地檢查了默認條件。 -
Google Pay
小組在Flutter
代碼中發(fā)現(xiàn)了一些錯誤勺阐,這些錯誤會在嘗試State在上下文之外訪問Flutter
對象時失敗的Widget
卷中。在實現(xiàn)null
安全之前,這些對象將返回null
并掩蓋錯誤渊抽;出于安全考慮蟆豫,可靠的分析器確定這些屬性永遠不會為空,并引發(fā)了分析錯誤懒闷。 -
Flutter
小組發(fā)現(xiàn)了一個錯誤十减,如果將該錯誤null
傳遞給中的scene
參數(shù)徙瓶,Flutter
引擎可能會崩潰Window.render()
。在進行null
安全遷移期間嫉称,他們添加了一個提示,將Scene
標記為non-nullable
灵疮,然后能夠輕松地防止可能觸發(fā)null的潛在應(yīng)用崩潰织阅。
4.默認情況下使用非空
一旦啟用空安全,變量聲明的基本改變震捣,因為默認的類型是不可為空:
// In null-safe Dart, none of these can ever be null.
var i = 42; // Inferred to be an int.
String name = getFileName();
final b = Foo();
如果要創(chuàng)建一個可以包含值或null
的變量荔棉,則需要在變量聲明中通過?
在類型中添加后綴來使其顯式:
// aNullableInt can hold either an integer or null.
int? aNullableInt = null;
空安全性的實現(xiàn)是健壯的,具有豐富的靜態(tài)流分析功能蒿赢,使的使用可空類型的工作變得更加容易润樱。例如,在檢查了null之后羡棵,Dart將局部變量的類型從nullable
提升為non-nullable
:
int definitelyInt(int? aNullableInt) {
if (aNullableInt == null) {
return 0;
}
// aNullableInt has now promoted to a non-null int.
return aNullableInt;
}
我們還添加了一個新關(guān)鍵字required
壹若。當命名參數(shù)被標記為required
(在Flutter小部件API中經(jīng)常發(fā)生)并且調(diào)用者忘記提供參數(shù)時,就會發(fā)生分析錯誤:
5.逐步遷移到無效安全性
因為可靠的安全性是對我們的打字系統(tǒng)的根本改變皂冰,所以如果我們堅持強制采用店展,那將是極度破壞性的。這樣秃流,你決定到時是正確的赂蕴,空安全是一項可選功能:你可以用Dart2.12,而無需被迫啟用空安全舶胀。您甚至可以依賴已經(jīng)啟用了空安全性的軟件包概说,無論您的應(yīng)用程序或軟件包是否啟用了空安全性。
為了幫助您將現(xiàn)有代碼遷移到null safety
的狀態(tài)嚣伐,我們提供了遷移工具和遷移指南糖赔。該工具首先分析所有現(xiàn)有代碼。然后纤控,您可以交互地查看該工具推斷的可空性屬性挂捻。如果您不同意該工具的任何結(jié)論,則可以添加可空性提示以更改推斷船万。添加一些遷移提示可能會對遷移質(zhì)量產(chǎn)生巨大影響刻撒。
目前,使用
dart create
和flutter create
不啟用可靠的空安全創(chuàng)建的新程序包和應(yīng)用程序耿导。當我們看到大多數(shù)生態(tài)系統(tǒng)已經(jīng)遷移時声怔,我們希望在將來的穩(wěn)定版本中對此進行更改。您可以輕松的在新創(chuàng)建的包或應(yīng)用中使用null safety
,可以使用命令dart migrate
舱呻。
6.Dart生態(tài)系統(tǒng)的零安全遷移狀況
在過去的一年中醋火,我們提供了幾種聲音無效安全性的預覽版和Beta版悠汽,目的是為生態(tài)系統(tǒng)植入支持無效性安全的軟件包。這項準備工作很重要芥驳,因為我們建議按順序遷移柿冲,以確保聲音的安全性-您不應(yīng)該在軟件包或應(yīng)用程序的所有依賴項都遷移之前就對其進行遷移。
我們已經(jīng)發(fā)布了Dart兆旬,F(xiàn)lutter假抄,F(xiàn)irebase和Material團隊提供的數(shù)百個軟件包的null安全版本。而且丽猬,我們已經(jīng)從驚人的Dart和Flutter生態(tài)系統(tǒng)中獲得了巨大的支持宿饱,因此pub.dev現(xiàn)在有超過一千個支持null安全的軟件包。重要的是脚祟,最流行的軟件包已首先遷移谬以,因此,對于今天的發(fā)布而言由桌,最流行的前100個軟件包中的98%为黎,前250個頂級軟件包中的78%和前500個頂級軟件包中的57%已及時支持零安全性。我們期待在未來幾周內(nèi)在pub.dev上看到更多具有空安全性的軟件包沥寥。我們的分析表明碍舍,pub.dev上的絕大多數(shù)軟件包已被解除阻止,可以開始遷移邑雅。
7.完全可靠的安全性的好處
完全遷移后片橡,Dart的null safety
就可以了。這意味著Dart 100%確保具有不可為null
的類型的表達式不能為null
淮野。當Dart分析您的代碼并確定某個變量不可為空時捧书,該變量始終為不可為空。Dart與Swift共享可靠的安全性骤星,但其他編程語言卻很少经瓷。
Dart的null safety
的健全性還具有另一個受歡迎的含義:這意味著您的程序可以更小,更快洞难。由于Dart確保不可為空的變量永遠不會為null
舆吮,因此Dart可以進行優(yōu)化。例如队贱,Dart提前(AOT)編譯器可以生成更小色冀,更快的本機代碼,因為當知道變量不是null
時柱嫌,它不需要添加對null
的檢查锋恬。
8.Dart FFI,用于將Dart與C庫集成
Dart FFI使您能夠利用C庫中的現(xiàn)有代碼编丘,以獲得更好的可移植性与学,并與經(jīng)過高度調(diào)整的C代碼集成以執(zhí)行對性能至關(guān)重要的任務(wù)彤悔。從Dart 2.12開始,Dart FFI已脫離Beta階段索守,現(xiàn)已被認為穩(wěn)定并且可以投入生產(chǎn)晕窑。我們還添加了一些新功能,包括嵌套結(jié)構(gòu)和按值傳遞結(jié)構(gòu)卵佛。
9.通過值傳遞結(jié)構(gòu)
可以在C代碼中按引用和按值傳遞結(jié)構(gòu)幕屹。FFI以前僅支持按引用傳遞,但從Dart 2.12開始级遭,您可以按值傳遞結(jié)構(gòu)。這是兩個同時通過引用和值傳遞的C函數(shù)的小示例:
struct Link {
double value;
Link* next;
};
void MoveByReference(Link* link) {
link->value = link->value + 10.0;
}
Coord MoveByValue(Link link) {
link.value = link.value + 10.0;
return link;
}
10.嵌套結(jié)構(gòu)
C API通常使用嵌套結(jié)構(gòu)-本身包含結(jié)構(gòu)的結(jié)構(gòu)渺尘,例如以下示例:
struct Wheel {
int spokes;
};
struct Bike {
struct Wheel front;
struct Wheel rear;
int buildYear;
};
從Dart 2.12開始挫鸽,F(xiàn)FI支持嵌套結(jié)構(gòu)。
11.API變更
為了聲明FFI穩(wěn)定并支持上述功能鸥跟,我們進行了一些較小的API更改丢郊。
現(xiàn)在禁止創(chuàng)建空結(jié)構(gòu)(打破更改#44622),并產(chǎn)生棄用警告医咨。您可以使用新的類型Opaque來表示空結(jié)構(gòu)枫匾。的dart:ffi
功能sizeOf
,elementAt
以及ref
現(xiàn)在需要編譯時類型參數(shù)(重大更改#44621)拟淮。因為package:ffi
已經(jīng)添加了新的便利功能干茉,所以在常見情況下,不需要分配和釋放內(nèi)存的額外樣板:
// Allocate a pointer to an Utf8 array, fill it from a Dart string,
// pass it to a C function, convert the result, and free the arg.
//
// Before API change:
final pointer = allocate<Int8>(count: 10);
free(pointer);
final arg = Utf8.toUtf8('Michael');
var result = helloWorldInC(arg);
print(Utf8.fromUtf8(result);
free(arg);
// After API change:
final pointer = calloc<Int8>(10);
calloc.free(pointer);
final arg = 'Michael'.toNativeUtf8();
var result = helloWorldInC(arg);
print(result.toDartString);
calloc.free(arg);
12.自動生成FFI綁定
對于較大的API曲面很泊,編寫與C代碼集成的Dart綁定可能非常耗時角虫。為了減輕這種負擔,我們構(gòu)建了一個綁定生成器委造,用于根據(jù)C
頭文件自動創(chuàng)建FFI包裝器
戳鹅。我們邀請您嘗試一下:package:ffigen
。
13.FFI路線圖
隨著核心FFI平臺的完成昏兆,我們將重點轉(zhuǎn)移到擴展FFI功能集枫虏,使其具有在核心平臺之上分層的功能。我們正在調(diào)查的一些功能包括:
- 特定于ABI的數(shù)據(jù)類型爬虱,例如
int
隶债,long
,size_t
(#36140) - 內(nèi)聯(lián)結(jié)構(gòu)中的數(shù)組(#35763)
- 打包的結(jié)構(gòu)(#38158)
- 聯(lián)合類型(#38491)
- 將終結(jié)器暴露給Dart(#35770饮潦;但是請注意燃异,您已經(jīng)可以使用C的終結(jié)器)
14.FFI的示例用法
我們已經(jīng)看到Dart FFI
的許多創(chuàng)造性用法,以與各種基于C的API集成继蜡。這里有一些例子:
-
open_file是用于跨多個平臺打開文件的單個
API
回俐。它使用FFI調(diào)用Windows
逛腿,macOS
和Linux
上的本機操作系統(tǒng)API。 -
win32封裝了最常見的
Win32 API
仅颇,從而可以直接從Dart調(diào)用各種Windows API
单默。 - objectbox是由基于C的實現(xiàn)支持的快速數(shù)據(jù)庫。
-
tflite_flutter使用FFI包裝
TensorFlow Lite API
忘瓦。
15.Dart語言的下一步是什么搁廓?
聲音無效安全性是我們幾年來對Dart語言所做的最大改變。接下來耕皮,我們將考慮在我們強大的基礎(chǔ)上對語言和平臺進行更多的增量更改境蜕。快速瀏覽一下我們在語言設(shè)計渠道中正在嘗試的一些事情:
類型別名(#65):可以為非函數(shù)類型創(chuàng)建類型別名凌停。例如粱年,您可以創(chuàng)建一個typedef并將其用作變量類型:
typedef IntList = List<int>;
IntList il = [1,2,3];
三重移位運算符(#120):添加了一個新的,完全可重寫的>>>
運算符罚拟,用于對整數(shù)進行無符號移位台诗。
通用元數(shù)據(jù)注釋(#1297):擴展元數(shù)據(jù)注釋以也支持包含類型參數(shù)的注釋。
靜態(tài)元編程(#1482):支持靜態(tài)元編程— Dart程序在編譯期間生成新的Dart源代碼赐俗,類似于Rust宏和Swift函數(shù)生成器拉队。該功能仍處于早期探索階段,但是我們認為它可以啟用當今依賴于代碼生成的用例阻逮。
16.Dart 2.12現(xiàn)已上市
Dutter 2.12
和Flutter 2.0 SDK
現(xiàn)已提供具有可靠的null safety
和穩(wěn)定的FFI
粱快。請花點時間查看Dart和Flutter的已知的null safety
問題。如果您發(fā)現(xiàn)任何其他問題叔扼,請在Dart問題跟蹤器中報告這些問題皆尔。
如果您已經(jīng)開發(fā)了發(fā)布在pub.dev上的軟件包,請立即查看遷移指南币励,并了解如何遷移以達到安全性慷蠕。遷移您的軟件包可能會幫助解除阻止其他依賴于該軟件包的軟件包和應(yīng)用程序。我們還要感謝已經(jīng)遷移的人食呻!
我們很想聽聽您在可靠安全性和FFI方面的經(jīng)驗流炕。在下面發(fā)表評論或通過推特給我們@dart_lang。
原文地址:https://medium.com/dartlang/announcing-dart-2-12-499a6e689c87