2019年谷歌开发者大会GDD
在上海举办的同时,Dart team
宣布推出稳定版本的Dart 2.5 SDK
,其中主要包括两个的新开发者功能的技术预览:ML Complete
- 由机器学习(ML)驱动的代码补全,以及用于调用C
代码的dart:ffi
外部函数接口。Dart 2.5
还改进了对常量表达式的支持。
此版本是实现最佳客户端优化语言愿景的进一步优化,可为任何平台快速创建应用程序。 ML Complete
是现有生产力工具套件的强大补充,如hot reload、customizable static analysis、Dart DevTools。 第二个预览功能dart:ffi
使您能够在运行Dart
代码的操作系统上利用现有的本机API
,以及用C
编写的现有跨平台本机库。
在过去一周新的IEEE Spectrum Top Programming Language 2019评级中,Dart
排到16名。
预览:ML代码补全
类型化编程语言的核心优势之一是,在类型中捕获的附加信息使IDE
/编辑器能够通过在输入代码时提供补全功能来帮助开发人员。 开发人员可以通过输入预期符号的开头并从提供的补全中进行选择来避免拼写错误并探索API
。
随着API
的增长,探索变得困难,因为可能的补全列表太长而无法按字母顺序浏览。 在过去的一年里,Dart team
一直在努力将机器学习应用于这个问题。通过分析大量GitHub
开源Dart
代码来训练基于给定上下文的可能成员事件的模型。模型由TensorFlow Lite提供,可用于预测开发人员正在编辑的下一个符号。称这个新功能为ML Complete
。 下面是使用Flutter
框架开发新的MyHome
小部件的示例:
如何试用ML Complete
ML Complete
直接内置于Dart
分析器中,因此可用于所有支持Dart
的编辑器,包括Android Studio
,IntelliJ
和VS Code
。有关如何选择使用此预览功能的详细信息,以及有关如何提供反馈和报告问题的详细信息,请参阅Wiki。
由于该功能仍在预览中,因此当前Flutter
和Dart
稳定版本中的不包括在以后版本中具有的性能和优化工作。 因此,建议预览此功能时临时使用Flutter dev channel
或Dart dev channel
。
预览:用于Dart-C互操作的ffi外部函数接口
目前,直接从Dart
调用C
仅限于使用本机扩展与Dart VM
深度集成。或者,Flutter
应用程序可以通过使用平台通道调用对应平台代码并从那里向前调用C
来间接使用C
。这是一种不友好的双重调用。希望提供一种新的机制,提供出色的性能,并且可以在许多支持的Dart
平台和编译器上运行。
Dart-C interop
支持两种主要方案:
- 在操作系统(OS)上调用基于C的系统API
- 调用基于C的库,可以是单个操作系统,也可以是跨平台
调用基于C的操作系统API
要将调用Linux
系统命令,传递给它的参数实际上是传递给shell/terminal
并在那里运行。 此命令的C header
:
// C header: int system(const char *command) in stdlib.h
任何互操作机制的核心挑战是处理两种语言的语义差异。 对于dart:ffi
,Dart
代码需要表达两件事:
- C函数及其参数和返回类型的类型
- 相应的Dart函数及其类型
// C header typedef:
typedef SystemC = ffi.Int32 Function(ffi.Pointer<Utf8> command);
// Dart header typedef:
typedef SystemDart = int Function(ffi.Pointer<Utf8> command);
接下来,使用与特定操作系统相关的编码对字符串参数进行编码,调用该函数,并再次释放参数内存:
// Allocate a pointer to a Utf8 array containing our command.
final cmdP = Utf8.toUtf8('open http://dart.dev');
// Invoke the command.
systemP(cmdP);
// Free the pointer.
cmdP.free();
此代码执行系统命令,导致系统默认浏览器打开dart.dev
:
调用基于C的框架和组件
dart:ffi
的第二个核心用途是调用基于C
的框架和组件。 本文讨论的基于ML
的代码补全就是一个具体的例子。它使用TensorFlow Lite
,这是一个基于C
的API
。使用dart:ffi
允许我们在需要提供代码补全的所有操作系统上运行TensorFlow
,具有本机TensorFlow
实现的高性能。如果想查看Dart TensorFlow
集成的代码,查看此repo。
包装API和代码生成
在描述函数和查找符号时会有一些编程开销。 可以从C header
生成许多样板代码。 所以目前专注于提供基础原语进行包装。
如何尝试dart:ffi
dart:ffi
库预览中发布。由于它仍处于预览状态,因此建议使用Flutter master channel
或Dart dev channel
,以便快速访问所做的更改和改进。
请注意,API可能会在现在和完成之间发生重大变化,因为会增加并扩大对常见模式的支持。
以下是应该了解的一些限制:
- 该库不支持嵌套结构,内联数组,打包数据或与平台相关的基本类型。
- 缺少指针操作的性能(但可以使用Pointer.asExternalTypedData来解决)。
- 该库不支持finalizers(当对象即将被垃圾收集时调用的回调)。
C interop
文档和dart:ffi API
参考文档记录了核心概念。
改进常量表达式
Dart
长期以来一直支持创建const
常量和值; 这些都是编译时常量,因此具有非常好的性能特征。 在以前的版本中,常量表达式有点受限。从Dart 2.5
开始,支持更多定义常量表达式的方法,包括使用强制转换的能力以及Dart 2.3
中提供的新控制流和集合扩展功能:
// Example: these are now valid compile-time constants.
const Object i = 3;
const list = [i as int];
const set = {if (list is List<int>) ...list};
const map = {if (i is int) i: "int"};
未来可能出现的功能
Dart team
正在为extension methods
、non-nullable
、以及一些早期的语言规划。还在研究改进的并发支持-例如在现代手机上更好地使用多核处理器的能力。
Dart team
为non-nullable
功能制定了一个雄心勃勃的计划,并且正在进行大量工作。最近几种新语言(如Kotlin)的设计从一开始就支持non-nullable
,而大多数现有语言(如Java)在后来的版本中添加了non-nullable
支持,这种语言仅限于额外的静态分析。简而言之,这意味着对非可空性的理解将扩展到类型系统的核心,一旦类型系统知道某些东西是非可空的,就可以完全信任这些信息,后端编译器可以自由地优化代码。这种稳健性在提供一致的“无异常体验”以及代码大小和运行时性能方面具有很大的优势。