27

LWN:简单介绍一下Dart!

 3 years ago
source link: https://mp.weixin.qq.com/s/Pxl-29PZuIlxxwd-sR8jXw
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

关注了就能看到更多这么棒的文章哦~

A look at Dart

By John Coggeshall
July 29, 2020
https://lwn.net/Articles/826315/

Dart,是 Google 发起的一个 BSD license 编程语言,有一个成熟的 open-source 社区在进行支持。Dart 支持多种体系架构,可以生成相应平台上的机器码(native machine-code binaries),也能把应用程序转化成 JavaScript 代码。Dart 的 1.0 版本是 2013 年发布的,而最新版本是 6 月 3 日发布的 2.8 版本(2.9 版本还在 public beta 阶段)。许多 open-source 项目都在使用 Dart,其中最著名的是跨平台的用户界面开发包(cross-device user-interface(UI) toolkit)Flutter。最近我们介绍过 Cananical 在 Flutter 上增加了投入,希望给 Linux 桌面带来更多的应用程序,而 Dart 就是这些开发工作的核心。

Dart 语法来自许多著名语言,如 JavaScript, PHP, C++,使他们的一个混合版。并且 Dart 拥有强类型(strongly-typed)的面向对象语言,基本类型都是由 class 来实现的。Dart 也包含一些 quirks(特有的特性),不过一般来说熟悉前面这些语言的开发者应该都可以很轻松地上手 Dart。Dart 自带了一些常用的基础类型,即 Lists(arrays),Sets(无顺序地集合),Maps(key/value 键值对)。

除了自带的基础类型,Dart core libraries 还提供了许多额外的功能,包括异步程序支持(asynchronous programming),HTML 相关操作,和支持 UTF-8 以及 JSON 的各种格式转换支持。

Dart compilation targets

为了给大家介绍 Dart 的编译功能,我们先需要准备一些代码。下面这个简单的例子是一个非常小的 Dart 应用程序,会计算出斐波那契数列:

/* Application entry point, just like C */
void main() {
int totalTerms = 45;
String output = "";

for(int i = 1; i <= totalTerms; i++) {
output += fibonacci(i).toString() + ", ";
}

print(output + "...");
}

/* A compact syntax for the recursive fibonacci algorithm */
int fibonacci(int n) => n <= 2 ? 1 : fibonacci(n - 2) + fibonacci(n - 1);

Dart 和 C 一样都用 main()函数作为程序入口。不过需要注意这里的 fibonacci()函数,这是一个参照 compact JavaScript 的语法,使用了 Dart 的箭头语法,配合一个条件表达式来实现一下这个算法。作为对比,下面是同样的一个 fibonacci()函数,不过更加清晰一些:

int fibonacci(int n) {
if(n <= 2) {
return 1;
}

return fibonacci(n - 2) + fibonacci(n - 1);
}

有许多方式来执行 Dart 程序。最直接的方式是利用 dart 命令在命令行上直接执行这段程序,这是利用了 Dart 虚拟机(virtual machine, VM)来实现的。Dart 的 VM 实现了 JIT(just-in-time)编译,会将 Dart 代码转换成机器码(native machine code)执行。下面是上述例子程序的输出内容:

$ dart fibonacci.dart
1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610,
987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368,
75025, 121393, 196418, 317811, 514229, 832040, 1346269,
2178309, 3524578, 5702887, 9227465, 14930352, 24157817,
39088169, 63245986, 102334155, 165580141, 267914296,
433494437, 701408733, 1134903170, ...

除了用 VM 来执行,Dart 还可以先用 dart2native 命令编译成机器码再执行。虽然我们一般称这个步骤为编译(compilation)步骤,不过这里 Dart 跟 C 等其他语言还是有一些区别的。Dart 语言天生并不要求所有代码都编译到机器码。原因是,Dart 应用程序可能直到在运行时(runtime)才能确认代码中某个变量的类型。这种情况下这部分代码就没法编译成可执行的机器码,而必须作为 bytecode 让 VM 进行解释执行。因此,哪怕编译过的 Dart 应用程序也仍然需要一个 runtime 运行时来解决这些问题。

dart2native 缺省会创建一个独立程序,把 runtime 打包在其中。也可以指定 dart2native 来创建 ahead-of-time (AOT) binary。这样的程序不会内嵌一个 runtime 环境,也无法直接执行。不过在提供了外部的 runtime 的时候就可以执行了,dartaotruntime 命令就可以达到目的。AOT 程序也可以用在基于 Dart 的云服务环境中,这样 runtime 就是由云服务缺省提供的。

最后,还可以通过 dart2js 来把 Dart 源代码“compile”成 JavaScript(这种技术被称为 Source-to-source compiler,即 transpiling)。文档中指出 dart2js 命令最适合 production build,因为整个程序都被编译成一个独立的优化过的 JavaScript 文件了。

文档中还推荐了 dartdevc 命令,用来方便开发过程。它跟 dart2js 的区别是 dartdevc 支持增量代码转换,这样就可以把一个 application 转换成多个独立的 JavaScript 文件。这样开发者平时开发的时候有了代码改动后只需要转换受影响的文件即可,不需要浪费时间来把全部代码都再转换一次。这个工具通常用在开发环境中的 web server 上,可以方便地在 Dart 源代码修改后使得 JavaScript 随时更新。在开发基于浏览器的 Dart application 的时候,Dart 还提供了一个开发环境的 web server,也就是 webdev 命令。此工具会在 Dart 程序开发过程中自动使用 dart2devc 来生成 JavaScript。

Getting to Dart

要想开始试着写自己的 Dart 程序,可以有几种选择。因为 Dart 可以转化为 JavaScript,那么最简单的方法就是使用 Dart 项目提供的 browser-based runtime 环境。本地安装 SDK 的话,可以参考 Dart 官方网站的步骤,包括 Linux 的 APT 源、基于 Chocolatey 的 Windows 安装包、或者通过 Homebrew 来安装 macOS 版本。

除了 Dart 自带的 Dart core libraries 之外,open-source 社区还提供了其他不少函数库。应用程序开发中最主要需要的就是 pub.dev 这个 package repository。Dart 在管理这些函数库的时候,使用了 pubspec.yaml 这个基于 YAML 的依赖关系文件,放置在项目根目录下。下面就是某个项目中的 pubspec.yaml 例子,其中我们定义了需要 pub.dev 的 basic_utils package:

name: LWN-Example
dependencies:
basic_utils: 2.5.5

Dart 提供了 pub 命令来下载此程序所以来的库文件。只需要在项目根目录下发起一条 pub get 命令就可以分析并安装好系统中的那些依赖库了。

这些依赖包缺省都认为是来子 Dart 的 pub.dev 仓库的。如果要用其他的仓库,Dart 还支持使用 Git 依赖关系,也就允许从 Git 仓库获取。pub 和 PHP 的 Composer 这个包管理工具类似,第一次执行时,也会在项目的 root 目录下生成一个相应的 pubspec.lock 文件,记录清楚此项目当前所用的依赖包的具体版本。后续调用 pub get 的时候会缺省使用这个文件,而不是 pubspec.yaml,这样确保项目中所有的依赖包的版本都是正确的。如果要升级依赖库到最新版本的话,就使用 pub upgrade 命令。

简要演示一下如何使用第三方库函数(当然也同时展示了语言的一些其他特性)。我们先建立一个简单的 Dart 命令行程序,来确定下面提供的字符串是不是一个 email 地址。这里利用了 basic_utils 函数库,其中包含了=EmailUtils::ismMail()= 函数方法:

import 'package:basic_utils/basic_utils.dart';

void main(List<String> arguments)
{
if (EmailUtils.isEmail(arguments[0])) {
print("It's an email!");
} else {
print("Not an email.");
}
}

这里我们先 import 了 basic_utils。 package: 这个前缀在 import 命令中就指明这是一个外部库,而不是项目中自己提供的函数库。import 操作会把 basic_utils 包中的所有 class 都导入进来,包括 EmailUtils 这个 class,我们就可以用它做邮件地址的验证了。

此例中,我们给 main()函数增加了一个参数。这个参数是个 List(array),其中元素都是 strings (String type)类型,此参数名为 argument。Dart 看到 main()函数有这个参数的话,在运行时就会把命令行参数展开提供出来。因为 List 是 Dart 内部的有索引的数组,那么 argument[0]就指向了命令附带的第一个参数(需要注意其他一些语言中 0 这个位置通常放的是程序名字本身):

$ dart package-demo.dart [email protected]
It's an email!

Wrapping up

Dart 这种语言在编写传统应用程序的时候有许多好处。主要是因为这也是 Dart 语言设计时的一个主要目标。开发者可以用任何语言来写程序,但每种语言在设计时通常都是针对某些特定目标场景的。Dart 在自己的项目主页上,称自己为“a client-optimized language for fast apps on any platform”,并且强调了自己是“language specialize around the needs of user interface creation”。Dart 追求的这个角度,是大多数其他语言都没有着重设计解决的领域。

本文中我们已经对 Dart 的一些浅层特性都进行了涵盖。我们对它进行了快速的了解,希望能帮助大家决定是不是值得后续投入。Dart 官方文档中的 tour of the language 和 tutorials 应该对想要开始试用 Dart 的人很有帮助。

LWN文章遵循CC BY-SA 4.0许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注LWN深度文章以及开源社区的各种新近言论~

640?wx_fmt=jpeg


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK