Dart - 快速入门(四)

文章目录[x]
  1. 1:泛型
  2. 1.1:在构造函数中使用泛型
  3. 1.2:限制泛型
  4. 2:Lib和其可见性
  5. 2.1:使用Lib
  6. 2.2:指定库的前缀
  7. 2.3:仅导入库的一部分
  8. 2.4:延迟加载库
  9. 3:异步支持
  10. 3.1:处理Future
  11. 3.2:定义异步函数
  12. 3.3:处理Steams
  13. 4:生成器函数
  14. 5:可调用类
  15. 6:Typedefs
  16. 7:注解
  17. 8:注释
  18. 8.1:单行注释
  19. 8.2:多行注释
  20. 8.3:文档注释

泛型

在List的API文档中,该类型实际上是List <E>。 <…>标记将List标记为通用(或参数化)类型-具有正式类型参数的类型。 按照惯例,大多数类型变量都具有单字母名称,例如E,T,S,K和V。

在构造函数中使用泛型

要在使用构造函数时指定一种或多种类型,将类型放在类名之后的尖括号(<...>)中。 例如:

var nameSet = Set<String>.from(names);

限制泛型

在实现通用类型时,可能希望限制其参数的类型。 可以使用extends来做到:

class Foo<T extends SomeBaseClass> {
// Implementation goes here...
String toString() => "Instance of 'Foo<$T>'";
}

class Extender extends SomeBaseClass {...}

Lib和其可见性

importlibrary指令可以帮助创建模块化且可共享的代码库。 库不仅提供API,而且是私有的:以下划线(_)开头的标识符仅在库内部可见。 每个Dart应用程序都是一个库,即使它不使用库指令。

使用Lib

使用import指定在一个库的范围内使用一个库:

import 'dart:html';

指定库的前缀

如果导入两个标识符冲突的库,则可以为一个或两个库指定一个前缀。 例如,如果library1library2都具有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();

仅导入库的一部分

如果只想使用库的一部分文件,则可以有选择地导入该库。 例如:

//仅仅导入foo
import 'package:lib1/lib1.dart' show foo;

// 导入除了 foo的所以其他
import 'package:lib2/lib2.dart' hide foo;

延迟加载库

延迟加载允许应用程序在需要库时以及在需要库时按需加载库。 在某些情况下,可以使用延迟加载:

1、为了减少网络应用的初始启动时间。

2、执行A/B测试:例如,算法的替代实现。

3、加载很少使用的功能,例如可选的屏幕和对话框。

注意:仅dart2js支持延迟加载。 Flutter,Dart VM和dartdevc不支持延迟加载。

要延迟加载库,必须使用deferred as导入它:

import 'package:greetings/hello.dart' deferred as hello;

当需要该库时,请使用库的标识符调用loadLibrary():

Future greet() async {
 await hello.loadLibrary();
 hello.printGreeting();
}

可以在库上多次调用loadLibrary()而不会出现问题。 该库仅加载一次。

异步支持

Dart的库有很多返回FutureStream对象的函数。 这些函数是异步的:它们在执行可能耗时的操作(例如I/O)之后返回,而无需等待该操作完成。

asyncawait关键字支持异步编程,可以编写看起来类似于同步代码的异步代码。

处理Future

使用asyncawait的代码是异步的,但是看起来很像同步代码。 例如,下面是一些使用await等待异步函数结果的代码:

await lookUpVersion();

要使用await,代码必须位于async函数中(标记为async的函数):

Future checkVersion() async {
 var version = await lookUpVersion();
 //...
}

使用trycatch来处理await代码中的错误:

try {
 version = await lookUpVersion();
} catch (e) {
 // ...
}

可以在异步函数中多次使用await。 例如,下面的代码等待三遍函数结果:

var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);

await表达式中,表达式的值通常是Future; 如果不是,则该值将自动包装在Future中。 此Future对象表示未来返回一个对象的承诺。 await表达式的值是返回的对象。 等待表达式使执行暂停,直到该对象可用为止。

定义异步函数

异步函数是一个函数,其主体带有async修饰符。

async关键字添加到函数将使其返回Future。 例如,考虑以下同步函数,该函数返回String

String lookUpVersion() => '1.0.0';

如果将其更改为异步函数(例如,由于将来的实现会很耗时),则返回的值将为Future

Future<String> lookUpVersion() async => '1.0.0';

请注意,该函数的主体不需要使用Future APIDart会在必要时创建Future对象。 如果函数无返回值,请使其返回类型为Future <void>

处理Steams

当需要从流中获取值时,使用async和异步for循环(await for )。

异步for循环具有以下形式:

await for (varOrType identifier in expression) {
 // 每次流发出一个值
}

表达式的值必须具有Stream类型。 执行过程如下:

1、等到流发出一个值。

2、执行for循环的主体,并将变量设置为该发射值。

3、重复1和2,直到关闭流。

要停止监听流,可以使用break或return语句,该语句会脱离for循环并取消订阅流。

Future main() async {
 // ...
 await for (var request in requestServer) {
 handleRequest(request);
 }
 // ...
}

生成器函数

当需要延迟生成值序列时,可以使用生成器函数。 Dart具有对两种生成器功能的内置支持:

1、同步生成器:返回一个Iterable对象。

2、异步生成器:返回一个Stream对象。

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

Iterable<int> naturalsTo(int n) sync* {
 int k = 0;
 while (k < n) yield k++;
}

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

Stream<int> asynchronousNaturalsTo(int n) async* {
 int k = 0;
 while (k < n) yield k++;
}

如果生成器是递归的,则可以使用yield*来提高其性能:

Iterable<int> naturalsDownFrom(int n) sync* {
 if (n > 0) {
 yield n;
 yield* naturalsDownFrom(n - 1);
 }
}

可调用类

为了允许像函数一样调用Dart类的实例,需要实现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);

Typedefs

Dart中,函数也是对象。 typedef可为函数类型提供一个别称,可以在声明字段和返回类型时使用该名称。 当将函数类型分配给变量时,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)或对常量构造函数的调用。

所有Dart代码都有两个注解:@deprecated@override。  如下时使用@deprecated注解的示例:

class Television {
/// _Deprecated: 使用 [turnOn] 代替._
@deprecated
void activate() {
turnOn();
}
void turnOn() {...}
}

可以定义自己的注解。 如下为定义带有两个参数的@todo注解的示例:

library todo;

class Todo {
final String who;
final String what;

const Todo(this.who, this.what);
}

下面为使用@todo的示例:

import 'todo.dart';

@Todo('seth', 'make this do something')
void doSomething() {
print('do something');
}

注解可以出现在库,类,typedef,泛型,构造函数,工厂,函数,字段,参数或变量声明之前,也可以出现在导入或导出指令之前。 可以在运行时使用反射来检索注解。

注释

Dart支持单行注释,多行注释和文档注释。

单行注释

void main() {
 // TODO: refactor into an AbstractLlamaGreetingFactory?
 print('Welcome to my Llama farm!');
}

多行注释

void main() {
/*
* This is a lot of work. Consider raising chickens.

Llama larry = Llama();
larry.feed();
larry.exercise();
larry.clean();
*/
}

文档注释

/// A domesticated South American camelid (Lama glama).
///
/// Andean cultures have used llamas as meat and pack
/// animals since pre-Hispanic times.
class Llama {
String name;

/// Feeds your llama [Food].
///
/// The typical llama eats one bale of hay per week.
void feed(Food food) {
// ...
}

/// Exercises your llama with an [activity] for
/// [timeLimit] minutes.
void exercise(Activity activity, int timeLimit) {
// ...
}
}

在生成的文档中,[Food]成为指向Food类的API文档的链接。

点赞

发表评论

昵称和uid可以选填一个,填邮箱必填(留言回复后将会发邮件给你)
tips:输入uid可以快速获得你的昵称和头像

Title - Artist
0:00