- 1:泛型
- 1.1:在构造函数中使用泛型
- 1.2:限制泛型
- 2:Lib和其可见性
- 2.1:使用Lib
- 2.2:指定库的前缀
- 2.3:仅导入库的一部分
- 2.4:延迟加载库
- 3:异步支持
- 3.1:处理Future
- 3.2:定义异步函数
- 3.3:处理Steams
- 4:生成器函数
- 5:可调用类
- 6:Typedefs
- 7:注解
- 8:注释
- 8.1:单行注释
- 8.2:多行注释
- 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和其可见性
import和library指令可以帮助创建模块化且可共享的代码库。 库不仅提供API,而且是私有的:以下划线(_)开头的标识符仅在库内部可见。 每个Dart应用程序都是一个库,即使它不使用库指令。
使用Lib
使用import指定在一个库的范围内使用一个库:
import 'dart:html';
指定库的前缀
如果导入两个标识符冲突的库,则可以为一个或两个库指定一个前缀。 例如,如果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();
仅导入库的一部分
如果只想使用库的一部分文件,则可以有选择地导入该库。 例如:
//仅仅导入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的库有很多返回Future或Stream对象的函数。 这些函数是异步的:它们在执行可能耗时的操作(例如I/O)之后返回,而无需等待该操作完成。
async和await关键字支持异步编程,可以编写看起来类似于同步代码的异步代码。
处理Future
使用async和await的代码是异步的,但是看起来很像同步代码。 例如,下面是一些使用await等待异步函数结果的代码:
await lookUpVersion();
要使用await,代码必须位于async函数中(标记为async的函数):
Future checkVersion() async {
var version = await lookUpVersion();
//...
}
使用try、catch来处理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 API。 Dart会在必要时创建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文档的链接。