生成器

当您需要延迟地生成一个值序列时,请考虑使用生成器函数。Dart内置支持两种生成器函数:

  1. 同步生成器:返回Iterable对象
  2. 异步生成器:返回Stream对象

要实现同步生成器函数,将函数体标记为sync*,并使用yield语句传递值:

  1. Iterable<int> naturalsTo(int n) sync* {
  2. int k = 0;
  3. while (k < n) yield k++;
  4. }

要实现异步生成器函数,将函数体标记为async*,并使用yield语句传递值:

  1. Stream<int> asynchronousNaturalsTo(int n) async* {
  2. int k = 0;
  3. while (k < n) yield k++;
  4. }

如果您的生成器是递归的,您可以使用yield*来改进它的性能:

  1. Iterable<int> naturalsDownFrom(int n) sync* {
  2. if (n > 0) {
  3. yield n;
  4. yield* naturalsDownFrom(n - 1);
  5. }
  6. }

有关生成器的更多信息,请参阅文章[Dart语言异步支持:Phase 2]。

可调用的类

实现call()方法可以让你的Dart类像函数一样被调用。

在下面的示例中,WannabeFunction类定义了一个call()函数,该函数接受三个字符串并将它们连接起来,每个字符串用空格分隔,并在结尾加一个感叹号。

  1. class WannabeFunction {
  2. call(String a, String b, String c) => '$a $b $c!';
  3. }
  4. main() {
  5. var wf = new WannabeFunction();
  6. var out = wf("Hi", "there,", "gang");
  7. print('$out');
  8. }
  1. ///执行结果
  2. Hi there, gang!

有关类的更多信息,请参见[Dart中的模拟函数]。

隔离器

大多数计算机,甚至在移动平台上,都有多核cpu。为了利用所有这些核心,开发人员通常使用同时运行的共享内存线程。但是,共享状态并发容易出错并且可能增加代码的复杂度。

不同于线程,所有Dart代码都运行在隔离器内部,而不是线程。每个隔离都有它自己的内存堆,确保任何其他隔离器都不能访问隔离状态。

有关更多信息,请参见[dart:isolate库文档]。

类型定义

在Dart中,函数是对象,就像字符串和数字是对象一样。typedef或function-type为函数提供一个类型别名,你可以在声明字段和返回类型时使用这个名称。当函数类型被分配给变量时,typedef保留类型信息。

以下代码不使用typedef:

  1. class SortedCollection {
  2. Function compare;
  3. SortedCollection(int f(Object a, Object b)) {
  4. compare = f;
  5. }
  6. }
  7. // Initial, broken implementation.
  8. int sort(Object a, Object b) => 0;
  9. void main() {
  10. SortedCollection coll = SortedCollection(sort);
  11. // All we know is that compare is a function,
  12. // but what type of function?
  13. assert(coll.compare is Function);
  14. }

当给compare分配f时类型信息会丢失。f的类型是(Object, Object)->int(int表示返回值类型),当然compare的类型是Function。如果我们更改代码以使用显式名称和保留类型信息,开发人员和工具都可以使用这些信息。

  1. typedef Compare = int Function(Object a, Object b);
  2. class SortedCollection {
  3. Compare compare;
  4. SortedCollection(this.compare);
  5. }
  6. // Initial, broken implementation.
  7. int sort(Object a, Object b) => 0;
  8. void main() {
  9. SortedCollection coll = SortedCollection(sort);
  10. assert(coll.compare is Function);
  11. assert(coll.compare is Compare);
  12. }

注意:目前,typedefs仅限于函数类型。我们期望这种情况会改变。

因为typedef仅仅是别名,所以它们提供了一种检查任何函数类型的方法。例如:

  1. typedef Compare<T> = int Function(T a, T b);
  2. int sort(int a, int b) => a - b;
  3. void main() {
  4. assert(sort is Compare<int>); // True!
  5. }

元数据

使用元数据提供关于代码的附加信息。元数据注释以字符@开头,后跟对编译时常量(如deprecated)的引用或对常量构造函数的调用。

所有Dart代码都可以使用两个注释:@deprecated和@override。有关使用@override的示例,请参见扩展类。这里有一个使用@deprecated注释的例子:

  1. class Television {
  2. /// _Deprecated: Use [turnOn] instead._
  3. @deprecated
  4. void activate() {
  5. turnOn();
  6. }
  7. /// Turns the TV's power on.
  8. void turnOn() {...}
  9. }

您可以定义自己的元数据注释。这里有一个定义带有两个参数的@todo注释的示例:

  1. library todo;
  2. class Todo {
  3. final String who;
  4. final String what;
  5. const Todo(this.who, this.what);
  6. }
  7. // 这里有一个使用@todo注释的例子:
  8. import 'todo.dart';
  9. @Todo('seth', 'make this do something')
  10. void doSomething() {
  11. print('do something');
  12. }

元数据可以出现在库、类、类型定义、类型参数、构造函数、工厂、函数、字段、参数或变量声明之前,也可以出现在导入或导出指令之前。您可以使用反射在运行时检索元数据。