参考:https://www.dartcn.com/guides/language/language-tour#%E6%B3%9B%E5%9E%8B
泛型
在 API
文档中你会发现基础数组类型 List
的实际类型是 List<E>
。<…>
符号将List
标记为 泛型 (或 参数化) 类型。 这种类型具有形式化的参数。 通常情况下,使用一个字母来代表类型参数, 例如 E, T, S, K, 和 V
等。
为什么使用泛型
在类型安全上通常需要泛型支持, 它的好处不仅仅是保证代码的正常运行:
- 正确指定泛型类型可以提高代码质量。
例如:
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
names.add(42); // 错误
- 使用泛型可以减少重复的代码。
例如,假设你创建了一个用于缓存对象的接口:
abstract class ObjectCache {
Object getByKey(String key);
void setByKey(String key, Object value);
}
后来发现需要一个相同功能的字符串类型接口,因此又创建了另一个接口:
abstract class StringCache {
String getByKey(String key);
void setByKey(String key, String value);
}
后来,又发现需要一个相同功能的数字类型接口 … 这里你应该明白了。
泛型可以省去创建所有这些接口的麻烦。 通过创建一个带有泛型参数的接口,来代替上述接口:
abstract class Cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
限制泛型类型
使用泛型类型的时候, 可以使用 extends
实现参数类型的限制。
class Foo<T extends SomeBaseClass> {
// Implementation goes here...
String toString() => "Instance of 'Foo<$T>'";
}
class Extender extends SomeBaseClass {...}
可以使用 SomeBaseClass
或其任意子类作为通用参数:
var someBaseClassFoo = Foo<SomeBaseClass>();
var extenderFoo = Foo<Extender>();
也可以不指定泛型参数:
var foo = Foo();
print(foo); // Instance of 'Foo<SomeBaseClass>'
指定任何非 SomeBaseClass 类型会导致错误:
var foo = Foo<Object>(); // 报错
库
import 和 library
指令可以用来创建一个模块化的,可共享的代码库。 库不仅提供了 API
,而且对代码起到了封装的作用: 以下划线 (_)
开头的标识符仅在库内可见。 每个 Dart
应用程序都是一个库 ,虽然没有使用 library
指令。
使用库
通过import
指定一个库命名空间中的内如如何在另一个库中使用。
例如,Dart Web
应用程序通常使用 dart:html
库,它们可以像这样导入:
import 'dart:html';
import
参数只需要一个指向库的 URI
。
- 对于内置库,
URI
拥有自己特殊的dart:
方案。 - 对于其他的库,使用系统文件路径或者
package:
方案 。
例如:
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();
导入库的一部分
如果你只使用库的一部分功能,则可以选择需要导入的 内容。例如:
// 只导入 foo 功能
import 'package:lib1/lib1.dart' show foo;
// 导入除了 foo 之外的所有功能
import 'package:lib2/lib2.dart' hide foo;
延迟加载库
Deferred loading (也称之为 lazy loading)
可以让应用在需要的时候再加载库。 下面是一些使用延迟加载库的场景:
- 减少 APP 的启动时间。
- 执行 A/B 测试,例如 尝试各种算法的 不同实现。
- 加载很少使用的功能,例如可选的屏幕和对话框。
要延迟加载一个库,需要先使用 deferred as
来导入:
当需要使用的时候,使用库标识符调用 loadLibrary()
函数来加载库:
import 'package:greetings/hello.dart' deferred as hello;
Future greet() async {
await hello.loadLibrary();
hello.printGreeting();
}
在一个库上你可以多次调用 loadLibrary()
函数。但是该库只是载入一次。
使用延迟加载库的时候,请注意一下问题:
- 延迟加载库的常量在导入的时候是不可用的。 只有当库加载完毕的时候,库中常量才可以使用。
- 在导入文件的时候无法使用延迟库中的类型。 如果你需要使用类型,则考虑把接口类型移动到另外一个库中, 让两个库都分别导入这个接口库。
- Dart 隐含的把
loadLibrary()
函数导入到使用deferred as
的命名空间 中。loadLibrary()
方法返回一个Future
对象,也就是异步函数。