做者 / Michael Thomsenhtml
Dart 2.12 现已发布,其中包含 健全的空安全 和 Dart FFI 的稳定版。空安全是咱们最新主打的一项生产力强化功能,意在帮助您规避空值错误,之前这种错误一般很难被发现,您能够观看下面这支视频了解详情。FFI 则是一种互操做机制,支持调用以 C 语言编写的既有代码,例如调用 Windows Win32 API。欢迎你们即刻开始使用 Dart 2.12。git
https://www.bilibili.com/vide...github
在详细了解健全空安全和 FFI 以前,咱们先来讨论一下它们在哪些方面契合了咱们对 Dart 平台的指望。编程语言每每有不少相似的功能,例如,不少语言都支持面向对象的编程或在 web 上运行。真正将各个语言区分开来的,是其独特的功能组合。web
Dart 具备横跨三个维度的独特功能组合:数据库
健全空安全加强了类型系统的稳健性,同时提升了性能。借助 Dart FFI,您能够得到更强的可移植性,同时沿用由 C 语言编写的既有代码,在处理对性能要求极为严苛的任务时,能够尽情使用通过精心优化的 C 语言代码。编程
自 Dart 2.0 中引入健全类型系统以来,Dart 语言中最重大的新增内容即是健全空安全。空安全进一步加强了类型系统,让您可以捕捉到空值错误,此类错误常常致使应用崩溃。启用空安全后,您就能够在开发过程当中捕捉到空值错误,避免应用在生产环境中发生崩溃。swift
健全空安全的设计围绕一套核心原则展开。您能够阅读 官方文档 了解这些原则对开发者的影响。后端
在空安全出现以前,开发者面临的核心挑战在于没法区分预期收到空值的代码和不接受空值的代码。几个月前,咱们在 Flutter 的 master 渠道中发现了一个错误,多个 flutter 工具命令在特定计算机配置下会发生崩溃,并触发空值错误: 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) { ...
您发现错误了吗?因为 version
可能为空,因此 major
和 minor
也可能为空。若是单独检查此处代码,这一错误彷佛并不难发现。但实际上,即便通过了严格的代码审查过程 (如 Flutter repo 所采用的代码审查流程),也老是不免有这样的漏网之鱼。在启用空安全后,静态分析可以当即捕捉到这一问题 (以下图)。您能够 在 DartPad 中亲自上手体验。安全
△ IDE 中的分析结果
这只是一个很是简单的错误。咱们早期在 Google 内部的代码中使用空安全时,捕捉到的复杂错误远多于此。其中一些是多年前就已经发现的 bug,但在经过空安全进行额外的静态检查前,不少团队都未能找到缘由。
启用空安全 后,声明变量的基础方法会发生变化,由于默认类型不可为空:
// 在空安全的 Dart 中,如下均不可为空 var i = 42; // Inferred to be an int. String name = getFileName(); final b = Foo();
若是您想要建立可能同时包含值或 null 的变量,则须要在声明变量时在类型后面显式添加 ? 后缀:
// aNullableInt 能够为整型或 null int? aNullableInt = null;
空安全的实现很稳健,并提供丰富的静态流程分析,方便开发者轻松处理可空类型。例如,局部变量在进行空值检查后,Dart 会将其类型从可空提高为非空:
int definitelyInt(int? aNullableInt) { if (aNullableInt == null) { return 0; } // aNullableInt 如今会被提示为非空 int return aNullableInt; }
咱们还添加了一个新的关键字,required。当一个命名的参数被标记为 required (在 Flutter widget API 中常常出现),而调用者忘记提供该参数时,就会发生以下分析错误:
空安全对于咱们的类型系统而言是一项根本性的改变,所以若是咱们执意强制全部开发者采用,势必会形成严重的混乱。所以,咱们想让您自行决定合适的迁移时机,空安全将是一项可选特性: 在作好准备以前,您能够在无需强制启用空安全的状况下使用 Dart 2.12。您甚至能够在还没有启用空安全的应用或 package 中依赖已启用空安全的 package。
为了帮助您将现有代码迁移至空安全,咱们提供了迁移工具和 迁移指南。该工具会首先分析您全部的代码,而后您能够交互式地查看工具推断出的可空属性,若是您不一样意工具得出的结论,则能够添加可空性提示以更改推断。添加迁移提示可能会大幅提高迁移质量。
目前,在默认状况下,使用 dart create 和 flutter create 新建立的 package 和应用中不会启用健全空安全。在大部分生态系统完成迁移后,咱们预计将在后续的稳定版本中默认启用。您能够经过 dart migrate
在新建立的 package 或应用中轻松 启用空安全。
去年,咱们提供了健全空安全的数个预览版和 Beta 版,旨在为生态系统提供首批支持空安全的 package。这项工做很是重要,咱们建议你们 有序迁移至健全空安全,也就是说,在全部依赖项迁移完成以前,最好不要迁移本身的 package 或应用。
咱们已发布由 Dart、Flutter、Firebase 和 Material 团队所提供的数百个 package 的空安全版本。使人惊喜的是,Dart 和 Flutter 生态系统对此也予以巨大的支持,pub.dev 如今共有 1,000 多个 package 支持空安全。并且重要的是,最受欢迎的 package 已率先完成迁移,截止到 Dart 2.12 发布时,前 100 个最受欢迎的 package 中已有 98 个支持空安全,而在前 250 和前 500 的 package 中,支持空安全的比例则为 78% 和 57%。咱们但愿在接下来的几周,pub.dev 上可以出现更多支持空安全的 package。咱们的分析 代表,pub.dev 上的绝大多数 package 已经能够 开始迁移。
完成迁移后,您的项目就处于健全的空安全模式下了。这意味着 Dart 可以彻底确保具备不可空类型的表达式不为空。当 Dart 分析完您的代码并肯定某个变量不可为空时,该变量将始终不可为空。Dart 与 Swift 都拥有健全的空安全,但有些编程语言在这方面仍有待改进。
Dart 的健全空安全还暗含另外一项备受期待的优点: 您的程序能够更小、更快。因为 Dart 可以确保不可为空的变量毫不为空,所以能够 实现优化。例如,Dart 的运行前 (ahead-of-time, AOT) 编译器能够生成更小更快的原生代码,由于当其知道变量不为空时,便再也不须要添加空值检查了。
您能够经过 Dart FFI 调用 C 语言编写的既有代码库,从而加强可移植性,还能够经过精心打磨的 C 代码完成对性能要求极为严苛的任务。从 Dart 2.12 起,Dart FFI 已结束 Beta 测试阶段,现已进入稳定状态,能够用于生产环境。咱们还添加了一些新功能,包括嵌套结构和按值传递结构。
在 C 语言中,结构可经过引用和值进行传递。FFI 之前仅支持按引用传递结构,但从 Dart 2.12 开始,也支持按值传递。下方的简单示例中,两个 C 函数使用引用和值完成传递:
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; }
C API 一般使用嵌套结构,这种结构自己也包含结构,好比如下示例:
struct Wheel { int spokes; }; struct Bike { struct Wheel front; struct Wheel rear; int buildYear; };
从 Dart 2.12 起,FFI 将支持嵌套结构。
做为 FFI 稳定版发布内容的一部分,而且为了支持上述功能,咱们作了一些小幅的 API 改动。
如今不容许建立空结构 (重要改动参照 #44622),并会给出弃用警告。您可使用一个新的类型 Opaque 来表示空结构。dart:ffi 函数 sizeOf、elementAt 和 ref 如今须要编译时的类型参数 (重要改动参照 #44621)。由于在 package:ffi 中增长了新的便利函数,因此在常见的状况下,无需额外添加关于分配和释放内存的模板代码:
// 分配一个 Utf8 数组,使用 Dart 字符串填充,而后传递给 C 方法并转换结果,最后释放 arg // // API 变动前: final pointer = allocate<Int8>(count: 10); free(pointer); final arg = Utf8.toUtf8('Michael'); var result = helloWorldInC(arg); print(Utf8.fromUtf8(result); free(arg); // API 变动后: final pointer = calloc<Int8>(10); calloc.free(pointer); final arg = 'Michael'.toNativeUtf8(); var result = helloWorldInC(arg); print(result.toDartString); calloc.free(arg);
对于大型的 API 接口,编写与 C 代码集成的 Dart 绑定极其耗时。为减轻这一负担,咱们为你们准备了绑定生成器,能够经过 C 头文件自动建立 FFI 封装代码,欢迎试用。
核心 FFI 平台完成后,咱们的工做重心将转向基于核心平台扩展 FFI 功能集。咱们正在研究的一些功能包括:
在过去的几个月中,咱们看到你们在使用 Dart FFI 集成一系列基于 C 语言的 API 时,发掘出了许多有创意的用法。下面介绍几个示例:
健全空安全是这几年咱们对 Dart 语言作出的最大改变。接下来,咱们将继续稳步改进 Dart 语言和平台。下面简单介绍一些咱们在 语言设计规划 中实验的内容:
typedef IntList = List<int>; IntList il = [1,2,3];
欢迎你们下载 Dart 2.12 和 Flutter 2.0 SDK,即刻开始使用 Dart 2.12,尽情体验健全空安全和稳定版 FFI。请你们阅览 Dart 和 Flutter 的已知空安全问题。若是您发现其余任何问题,请在 Dart 问题跟踪页 中报告给咱们。
若是您已在 pub.dev 上发布了 package,请当即参阅 迁移指南,了解如何迁移至健全空安全。迁移有助于依赖您的 package 的其余 package 和应用完成迁移。咱们在此向已经完成迁移的开发者们表示感谢!
欢迎你们与咱们分享本身的健全空安全和 FFI 体验,咱们评论区见!