作者 / Kevin Moore & Michael Thomsen

Dart 2.13 版现已发布,其中新增了类型别名功能,这是目前用户呼声第二高的语言功能。Dart 2.13 还改进了 Dart FFI 以及更好的性能,并且我们还为 Dart 提供了新的官方镜像。本文将为您奉上 2.12 版中推出的空安全功能的最新信息,介绍 2.13 版本的新特性,以及 Docker 和 Google Cloud 对 Dart 后端支持的新消息。另外,还会预告在后续版本中的其他变化。

空安全更新

在今年 3 月份发布的 Dart 2.12[1] 中,我们推出了 健全的空安[2] 全功能。空安全可谓是 Dart 最近推出的一项重要功能,旨在帮助您避免空值错误 (这类错误经常难以发现),有效提升工作效率。我们希望发布 package 的开发者能够及时跟进这项发布,更新 pub.dev 上分享的 package 以支持空安全。

我们极其欣喜地看到,在发布后的短短几个月内,空安全就已被广泛采用,目前 pub.dev 上前 500 个最受欢迎的 package 中,93% 的 package 已经支持空安全。 在此,谨向如此迅速跟进的所有 package 开发者致以最诚挚的谢意,感谢大家帮助推动整个生态系统不断向前!

有了这么多 package 支持空安全,您就可以开始考虑着手将自己的应用迁移到使用空安全的环境。要开始迁移,请首先使用 dart pub outdated 检查应用的依赖项。详细步骤,请参阅 空安全迁移指南[3]。我们还调整了 dart createflutter create 模板,现在它们在新的应用程序和 package 中默认启用空安全。

推出类型别名功能

类型别名是 2.13 版中新增的语言功能,也是广大开发者翘首以盼的功能,曾在语言问题的反馈中高居 第二位[4]。有了这一功能,开发者就能够创建函数类型的别名,但不能创建其他任何类型。

利用类型别名您可以为任何现有的类型创建新的名称,然后将新创建的名称用在原始类型可以出现的任何地方。创建新名称并不会真的定义一个新类型,只不过是引入一个简短的别名而已。该别名甚至能通过类型等同测试:

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

那么,类型别名可以怎么用?一种常见的用法是给某类型指定一个更短或更具描述性的名称,以便您的代码更易于理解和维护。

比如,给 JSON 类型指定别名就是种不错的用法 (此示例由 GitHub 用户 Levi-Lesches[5] 提供,特此感谢)。在下列示例中,我们可以定义一个新的类型别名 Json,它将一个 JSON 文档描述为一个 map,其键为 String,值为任意值 (使用动态类型)。这样,当我们定义名为 fromJson 的构造函数和 json get函数时,就能使用该 Json 类型别名。

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,};
}

您也可以对指代某个类的类型别名调用构造函数,比如以下示例就非常合规:

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

通过使用类型别名来指代复杂类型,可以让读者更容易理解您代码的不变量。例如,以下代码定义了一个类型别名来描述键值为泛型类型 X、值为类型 List<X> 的映射。如果给该类型指定一个具有单一类型参数的名称,映射的常规结构在代码读者眼中会变得更为清晰。

typedef MapToList<X> = Map<X, List<X>>;
void main() {MapToList<int> m = {};m[7] = [7]; // OKm[8] = [2, 2, 2]; // OKfor (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 类,您想要将它重命名为 BetterNamedClass。如果您只是重命名该类,那么您的 API 客户那边将会出现突发编译错误。而使用类型别名,则不会出现这一问题,您可以随意重命名,只不过要先为旧的类名称定义一个新的类型别名,再给旧名称添加几行 @Deprecated 注解。这样,使用 PoorlyNamedClass 的代码虽然会出现警告,但仍可继续编译并照旧正常运行,让用户有时间升级其代码。

mylibrary.dart:class BetterNamedClass {}@Deprecated('Use BetterNamedClass instead')
typedef PoorlyNamedClass = BetterNamedClass;main.dartimport 'mylibrary.dart';void main() {PoorlyNamedClass p;
}=>'PoorlyNamedClass' is deprecated and shouldn't be used. Use BetterNamedClass instead.

下面介绍实现 BetterNamedClass 和弃用 PoorlyNamedClass 的方法 (在一个名为 mylibrary.dart 的文件中)。

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

下面是尝试使用 PoorlyNamedClass 时会发生的情况:

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

类型别名功能从 Dart 2.13 版开始即可使用,要启用此功能,需要将您 pubspec 中版本较低的 Dart SDK 约束设置为最低 2.13 版,如下所示:

environment:sdk: ">=2.13.0 <3.0.0"

此功能支持向后兼容,这要归功于 语言的版本管理[6]。也就是说,SDK 约束版本低于 2.13 的 package 可以安全地引用 2.13 版 package 中定义的类型别名,尽管 2.13 版之前的 package 不能定义其自己的类型别名。

Dart 2.13 FFI 的变化

我们还在 Dart FFI (这是用来调用 C 语言代码的互操作机制) 中引入了一些新功能。

首先,FFI 现在支持包含内联数组 (#35763[7]) 的结构。假设某 C 语言结构具有如下内联数组:

struct MyStruct {uint8_t arr[8];
}

现在,只需将包含一个类型实参的元素类型指定给 Array,即可直接将该结构体封装在 Dart 中,如下所示:

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

其次,FFI 现在支持封装结构体 (#38158[8])。结构体通常都被放置在内存中,以便其位于地址边界内的成员能够被 CPU 更轻松地存取。使用 封装结构体[9] 时,为了减少整体内存占用量,经常会以平台特有的方式忽略一些填充字节。借助新的 @Packed(<alignment>) 注解,您可以轻松指定填充字节。例如,下列代码创建的结构体就指定其在内存中时的字节对齐为 4。

@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 在性能方面的提升

我们一直在不断努力降低 Dart 代码的应用体量和内存占用量。在大型 Flutter 应用中,经过 AOT 编译 Dart 程序的元数据的内部结构可能要占用非常可观的内存。这些元数据的存在大多是为了实现热重载、交互式调试,以及格式化可读堆栈轨迹等功能,这些功能在需要部署的应用中从不会用到。过去几年来,我们一直在重构 Dart 原生运行时环境,以便尽可能多地消除这种开销。其中一些改进适用于所有以版本模式构建的 Flutter 应用,而有些则需要使用 --split-debug-info[10] 标志将 AOT 编译应用中的调试信息拆分出来,从而放弃可读的堆栈轨迹。

Dart 2.13 在内存消耗上取得了很大的进步,在使用 --split-debug-info 时,程序元数据占用的空间量降幅显著。例如,Flutter Gallery 的空间占用降幅达到 30%: 在 --split-debug-info 模式下,程序元数据在 Dart 2.12 中要占用 5.7Mb,而在 Dart 2.13 中仅需 3.7Mb。以 Flutter Gallery 应用为例,在 Android 平台上,包含调试信息的发布 APK 大小为 112.4MB,不包含的情况下大小为 106.7MB (总体积减少了 5%)。该 APK 中包含了大量的资源。仅从 APK 内部的元数据体积来说,从 Dart 2.12 平台上的 5.7MB 减少至 Dart 2.13 平台上的 3.7MB (减少了35%!)。

如果对您来说应用体量和内存占用量比较重要,可以使用 --split-debug-info[11] 标志省略调试信息。请注意,一旦这么做,您需要使用 symbolize 命令[12] 来重新使堆栈轨迹可读。

Dart 官方 Docker 镜像发布以及 Cloud 支持

Dart 现在在 官方镜像[13] 中可用,虽然 Dart 早已提供了 Docker 镜像,但为了遵循最佳实践,这些 新的 Dart 镜像[14] 是由 Docker 进行测试和验证的。它们还支持 AOT 编译,可以大大减少构建容器的大小,并且可以在容器环境中提升部署速度——如 Cloud Run[15]

虽然 Dart 始终专注于使 Flutter 等应用框架在每个屏幕上构建出色的界面,但我们意识到,大多数用户体验的背后至少有一个托管服务。通过让 Dart 轻松构建后端服务来支持全栈体验,开发者可以使用与前端 widget 相同的语言和业务逻辑,将他们的应用扩展到云端。

通常来说,将 Dart 用于 Flutter 应用程序的后端,特别符合 Google 无服务器管理平台 Cloud Run 的简单性和可扩展性。这也包括零扩展,意味着当您的后端不处理任何请求时,就不会产生成本。我们与 Google Cloud 团队合作,提供 Dart 的函数框架[16],这是一个 packages、工具和实例的集合,使开发者们能够轻松地编写 Dart 函数,以取代处理 HTTP 请求和 CloudEvents 的完整服务器部署。

您可以查看我们的 Google Cloud 官方文档[17] 以便开始使用。

后续更新预告

在接下来的版本中,还会有一些令人激动的改变。和以往一样,您可以使用 language funnel[18] 追踪器留意我们的后续工作。

我们一直努力改进的一个方面是,为 Dart 和 Flutter 定义一组新的 canonical lint。lint 是配置 Dart 静态分析[19] 的一种高效方式,但由于可能有成百上千个 lint 要启用或禁用,有时可能会难以抉择。眼下,我们正打算定义两组要在 Dart 和 Flutter 项目中默认应用的 canonical lint。预计这两组 lint 将在下一个稳定版中默认启用。如果您想要提前预览,请查看 lints[20] 和 flutter_lints[21] 这两个 package。

最后,如果您深度嵌套了 Dart VM 运行时环境,请注意,我们打算弃用其现有的机制。我们将用一个基于 Dart FFI 的更快、更灵活的模型取代它 (请参阅追踪问题 #45451[22])。

Dart 2.13 版现已发布

Dart 2.13 版现已在 Dart 2.13[23] 和 Flutter 2.2[24] SDK 中推出,此版本新增了类型别名功能,还改进了 FFI。

如果您一直在等待将自己的依赖项迁移到空安全环境的时机,不妨使用 dart pub outdated[25] 再次检查一下。目前,前 500 个最受欢迎的 package 中,93% 的 package 都已迁移,现在没准就是您迁移的好时机。在此,谨向那些已经迁移的开发者致以最衷心的感谢!

欢迎试用本指南中介绍的新功能和改进后的功能,并将您使用后的感想告诉我们。请在下方评论区留言。

参考资料

[1]

Dart 2.12: https://flutter.cn/posts/announcing-dart-2-12

[2]

健全的空安: https://dart.cn/null-safety

[3]

空安全迁移指南: https://dart.cn/null-safety/migration-guide#step1-wait

[4]

第二位: https://github.com/dart-lang/language/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc

[5]

Levi-Lesches: https://github.com/Levi-Lesches

[6]

语言的版本管理: https://dart.cn/guides/language/evolution#language-versioning

[7]

#35763: https://github.com/dart-lang/sdk/issues/35763

[8]

#38158: https://github.com/dart-lang/sdk/issues/38158

[9]

封装结构体: http://www.catb.org/esr/structure-packing/

[10]

--split-debug-info: https://flutter.cn/docs/perf/app-size#reducing-app-size

[11]

--split-debug-info: https://flutter.cn/docs/perf/app-size#reducing-app-size

[12]

symbolize 命令: https://flutter.cn/docs/deployment/obfuscate#reading-an-obfuscated-stack-trace

[13]

官方镜像: https://docs.docker.com/docker-hub/official_images/

[14]

新的 Dart 镜像: https://hub.docker.com/_/dart

[15]

Cloud Run: https://cloud.google.com/run

[16]

Dart 的函数框架: https://pub.dev/packages/functions_framework

[17]

Google Cloud 官方文档: https://dart.cn/server/google-cloud

[18]

language funnel: https://github.com/dart-lang/language/projects/1

[19]

静态分析: https://dart.cn//guides/language/analysis-options

[20]

lints: https://pub.dev/packages/lints

[21]

flutter_lints: https://pub.dev/packages/flutter_lints

[22]

#45451: https://github.com/dart-lang/sdk/issues/45451

[23]

Dart 2.13: https://dart.cn/get-dart

[24]

Flutter 2.2: https://dart.cn/get-dart

[25]

dart pub outdated: https://dart.cn/null-safety/migration-guide

Dart 2.13 版现已发布相关推荐

  1. InterSystems IRIS、IRIS for Health和Health Connect 2021.1预览版现已发布

    InterSystems IRIS.IRIS for Health和HealthShare Health Connect的2021.1版本的预览版现已发布. 由于这是一个预览版,我们希望在下个月的通用 ...

  2. ML Kit 正式版现已发布!新增自拍人像抠图功能

    文 / ML Kit 产品经理 Kenny Sulaimon:ML Kit 软件工程师 Chengji Yan.Suril Shah.Buck Bourdon:ML Kit 技术主管 Shiyu Hu ...

  3. Microsoft Message Analyzer (微软消息分析器,“网络抓包工具 - Network Monitor”的替代品)官方正式版现已发布...

    来自官方日志的喜悦 被誉为全新开始的消息分析器时代,由MMA为您开启,博客原文写的很激动,大家可以点击这里浏览:http://blogs.technet.com/b/messageanalyzer/a ...

  4. 适用于 Flutter 的 Google 移动广告 SDK 正式版现已发布

    作者 / Zoey Fan,Flutter 产品经理 应用变现有多种方法: 通过实体企业的店面接受付款.提供订阅或应用内购买,或者直接在应用中投放广告.经过六个月的 beta 测试期,我们很高兴能够推 ...

  5. Delphi 和 C++Builder 免费社区版更新至 10.4.2 版现已发布!

    Delphi 和 C++Builder 的免费且功能齐全的社区版旨在帮助您开始编程.这些强大的 IDE 提供了快速探索强大的应用程序开发所需的所有功能. 社区版发布后,社区中的学生和爱好者可以免费使用 ...

  6. Android 12开发者预览版现已发布,包含众多亮点,Android码农是如何进入腾讯的

    Android 12 将支持空间音频与MPEG-H,并为高达24个音频通道进行了优化(之前仅有8个).它还将使开发者更容易将「隆隆声」效果与音频联系起来. 谷歌似乎正在将注意力放在AV1图像文件格式( ...

  7. Android 测试支持库 1.0 现已发布!

    我们非常高兴地宣布,Android 测试支持库 (ATSL) 1.0 版现已发布. ATSL 1.0 版对现有测试 API 进行了重要更新,不仅添加了许多新功能.还提升了性能和稳定性,同时还修复了若干 ...

  8. Dart 2.12 现已发布

    作者 / Michael Thomsen Dart 2.12 现已发布,其中包含 健全的空安全[1] 和 Dart FFI[2] 的稳定版.空安全是我们最新主打的一项生产力强化功能,意在帮助您规避空值 ...

  9. 英特尔® Distribution of OpenVINO™ toolkit 2021 版的发布说明

    注意 2020 版的发布说明,请参阅英特尔® Distribution of OpenVINO™ toolkit 2020 版的发布说明. 简介 英特尔® Distribution of OpenVI ...

最新文章

  1. javer的表结构设计
  2. python解析xml文件选用模块_python-minidom模块【解析xml】
  3. js断点和调试学习总结3
  4. 第一章 编程基础知识
  5. 装饰器补充、三元表达式、生成式、匿名函数
  6. 【Django】The view userWeb.views. didn‘t return an HttpResponse object. It returned None instead.
  7. MATLAB通信仿真实例1:无噪声信道下DSB-SC调制解调器
  8. python模拟登陆豆瓣_模拟登陆豆瓣并爬取个人主页(爬虫项目三)
  9. vue 项目实现短信发送
  10. Java小农养成记第一天
  11. 2017安防民用市场现状及特点浅析
  12. 9. 【gRPC系列学习】连接失败处理:backoff协议
  13. Evil.js代码杀手
  14. TX2 用文件IO的方式操作GPIO
  15. mysql英文版数据库备份方法_mysql数据库太大了如何备份与还原
  16. 常见临近点算子的求解
  17. linux下运行讯飞语音云的测试程序
  18. 数字电路 电平转换总结
  19. 剑指Offer-五只猴子吃桃子
  20. 【wikioi】1034 家园(最大流+特殊的技巧)

热门文章

  1. springboot 整合 MongoDB 实现登录注册,html 页面获取后台参数的方法
  2. DCDC的开关节点SW能打孔吗?
  3. ArcGIS、Super、MapMapInfo…
  4. 是科学还是魔法?Informer on MindSpore——时间序列预测技术实践
  5. 机器学期第一学期小结
  6. bios设置自动开机
  7. 智能优化算法之鸟群算法(BSA)的实现(Python附源码)
  8. 我的第一个长程序,虽然是直接抄了书上,可是还是出现了两次拼写错误,最终还是找到异常的答案,改过来了。...
  9. Low-Light Image Enhancement with Normalizing Flow
  10. LVS原理详解(3种工作模式及8种调度算法)