一、库
库和可见性
import 和 library 关键字可以帮助你创建一个模块化和可共享的代码库。代码库不仅只是提供 API 而且还起到了封装的作用:以下划线(_)开头的成员仅在代码库中可见。每个 Dart 程序都是一个库,即便没有使用关键字 library 指定。
使用库
使用 import 来指定命名空间以便其它库可以访问。
//可以导入代码库 [dart:html](https://api.dart.dev/stable/dart-html) 来使用 Dart Web 中相关 API:
import 'dart:html';
import
的唯一参数是用于指定代码库的 URI,对于 Dart 内置的库,使用 dart:xxxxxx 的形式。而对于其它的库,你可以使用一个文件系统路径或者以 package:xxxxxx 的形式。package:xxxxxx 指定的库通过包管理器(比如 pub 工具)来提供:
import 'package:test/test.dart';
指定库前缀
如果你导入的两个代码库有冲突的标识符,你可以为其中一个指定前缀。比如如果 library1 和 library2 都有 Element 类,那么可以这么处理:
import 'package:lib1/lib1.dart';
import 'package:lib2/lib2.dart' as lib2;
// 使用 lib1 的 Element 类。
Element element1 = Element();
// 使用 lib2 的 Element 类。
lib2.Element element2 = lib2.Element();
导入库的一部分
如果你只想使用代码库中的一部分,你可以有选择地导入代码库。例如:
// 只导入 lib1 中的 foo。(Import only foo).
import 'package:lib1/lib1.dart' show foo;
// 导入 lib2 中除了 foo 外的所有。
import 'package:lib2/lib2.dart' hide foo;
延迟加载库
延迟加载(也常称为 懒加载)允许应用在需要时再去加载代码库,下面是可能使用到延迟加载的场景:
- 为了减少应用的初始化时间。
- 处理 A/B 测试,比如测试各种算法的不同实现。
- 加载很少会使用到的功能,比如可选的屏幕和对话框。
使用 deferred as 关键字来标识需要延时加载的代码库:
import 'package:greetings/hello.dart' deferred as hello;
//当实际需要使用到库中 API 时先调用 loadLibrary 函数加载库:
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
在前面的代码,使用 await
关键字暂停代码执行直到库加载完成。更多关于 async
和 await
的信息请参考异步支持。
loadLibrary 函数可以调用多次也没关系,代码库只会被加载一次。
当你使用延迟加载的时候需要牢记以下几点:
-
延迟加载的代码库中的常量需要在代码库被加载的时候才会导入,未加载时是不会导入的。
-
导入文件的时候无法使用延迟加载库中的类型。如果你需要使用类型,则考虑吧接口类型转移到另一个库中然后让两个库都分别导入这个接口库。
-
Dart会隐式地将
loadLibrary
方法导入到使用了deferred as *命名空间*
的类中。loadLibrary
函数返回的是一个 Future。
二、异步支持
Dart 代码库中有大量返回 Future 或 Stream 对象的函数,这些函数都是 异步 的,它们会在耗时操作(比如I/O)执行完毕前直接返回而不会等待耗时操作执行完毕。
async 和 await 关键字用于实现异步编程,并且让你的代码看起来就像是同步的一样。
处理 Future
可以通过下面两种方式,获得 Future 执行完成的结果:
- 使用
async
和await
; - 使用 Future API,具体描述,参考库概览。
使用 async 和 await 的代码是异步的,但是看起来有点像同步代码。例如,下面的代码使用 await 等待异步函数的执行结果。
await lookUpVersion();
必须在带有 async 关键字的 异步函数 中使用 await:
Future checkVersion() async {
var version = await lookUpVersion();
// 使用 version 继续处理逻辑
}
尽管异步函数可以处理耗时操作,但是它并不会等待这些耗时操作完成,异步函数执行时会在其遇到第一个
await
表达式(详情见)的时候返回一个 Future 对象,然后等待 await 表达式执行完毕后继续执行。
声明异步函数
定义 异步函数 只需在普通方法上加上 async 关键字即可。
将关键字 async 添加到函数并让其返回一个 Future 对象。假设有如下返回 String 对象的方法:
String lookUpVersion() => '1.0.0';
//将其改为异步函数,返回值是 Future:
Future<String> lookUpVersion() async => '1.0.0';
注意,函数体不需要使用 Future API。如有必要,Dart 会创建 Future 对象。
如果函数没有返回有效值,需要设置其返回类型为 Future<void>。
处理 Stream
如果想从 Stream 中获取值,可以有两种选择:
- 使用
async
关键字和一个 异步循环(使用await for
关键字标识)。 - 使用 Stream API。详情参考库概览。
可调用类
通过实现类的 call() 方法,允许使用类似函数调用的方式来使用该类的实例。
在下面的示例中,WannabeFunction 类定义了一个 call() 函数,函数接受三个字符串参数,函数体将三个字符串拼接,字符串间用空格分割,并在结尾附加了一个感叹号。
class WannabeFunction {
String call(String a, String b, String c) => '$a $b $c!';
}
var wf = WannabeFunction();
var out = wf('Hi', 'there,', 'gang');
main() => print(out);
隔离区
大多数计算机中,甚至在移动平台上,都在使用多核 CPU。为了有效利用多核性能,开发者一般使用共享内存的方式让线程并发地运行。然而,多线程共享数据通常会导致很多潜在的问题,并导致代码运行出错。
为了解决多线程带来的并发问题,Dart 使用 isolates 替代线程,所有的 Dart 代码均运行在一个 isolates 中。每一个 isolates 有它自己的堆内存以确保其状态不被其它 isolates 访问。
类型定义
在 Dart 语言中,函数与 String 和 Number 一样都是对象,可以使用 类型定义(或者叫 方法类型别名)来为函数的类型命名。使用函数命名将该函数类型的函数赋值给一个变量时,类型定义将会保留相关的类型信息。
比如下面的代码没有使用类型定义:
class SortedCollection {
Function compare;
SortedCollection(int f(Object a, Object b)) {
compare = f;
}
}
// 简单的不完整实现。
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
// 我们知道 compare 是一个函数类型的变量,但是具体是什么样的函数却不得而知。
assert(coll.compare is Function);
}
上述代码中,当将参数 f 赋值给 compare 时,函数的类型信息丢失了,这里 f 这个函数的类型为 (Object, Object) → int(→ 代表返回),当然该类型也是一个 Function 的子类,但是将 f 赋值给 compare 后,f 的类型 (Object, Object) → int 就会丢失。我们可以使用 typedef 显式地保留类型信息:
typedef Compare = int Function(Object a, Object b);
class SortedCollection {
Compare compare;
SortedCollection(this.compare);
}
// 简单的不完整实现。
int sort(Object a, Object b) => 0;
void main() {
SortedCollection coll = SortedCollection(sort);
assert(coll.compare is Function);
assert(coll.compare is Compare);
}
元数据
使用元数据可以为代码增加一些额外的信息。元数据注解以 @ 开头,其后紧跟一个编译时常量(比如 deprecated)或者调用一个常量构造函数。
@deprecated 和 @override
class Television {
/// _弃用: 使用 [turnOn] 替代_
@deprecated
void activate() {
turnOn();
}
/// 打开 TV 的电源。
void turnOn() {...}
}
网友评论