在查看基本数组类型List的API文档,会看到该类型实际上是List
为什么要使用泛型
类型安全通常需要泛型,除了允许让代码运行之外,还可以:
- 正确指定泛型类型会生成更好的代码。
例如,可以使用List
1
2
3
var names = List<String>();
names.addAll(['a', 'b', 'c']);
// names.add(1); // 错误
- 可以减少代码重复。
泛型允许我们在多种类型之间共享单个接口和实现,同时仍然利用静态分析。例如,创建一个用于缓存对象的接口:
1
2
3
4
5
// 抽象类
abstract class ObjectCache {
Object getByKey(String key);
void setByKey(String key, Object value);
}
当缓存字符串对象时,需要创建另一个版本,实际上写法相差无异,只是类型不一致。
1
2
3
4
abstract class StringCache {
String getByKey(String key);
void setByKey(String key, String value);
}
此时会发现使用泛型可以省去这些麻烦,使用泛型示例:
1
2
3
4
abstract class cache<T> {
T getByKey(String key);
void setByKey(String key, T value);
}
上面示例中的T只是替身类型,在这里充当一个占位符,可视为开发人员稍后定义的类型。
使用集合文字
列表(List),集合(Set),和映射(Map)可以参数化。参数化文字对列表和集合来说在其前面加上
1
2
var namesList = <String>['a', 'b', 'c'];
var uniqueNames = <String>{'a', 'b', 'c'};
对映射(Map)来说,在其前面加上<keyType, valueType>,例如:
1
2
3
4
5
var pages = <String, String> {
'index.html' : 'Homepage',
'robots.txt' : 'Hints for web robots',
'humans.txt' : 'we are people, not machines'
};
使用带有参数类型的构造函数
要在使用构造函数时指定一个或多个类型,请将类型放在类名称后面的尖括号<...>
中。例如:
1
2
3
4
// 集合
var nameSet = Set<String>.from(names);
// Map
var views = Map<int, View>();
通用集合及其包含的类型
Dart的泛型是具体的,也就是说他们在运行时会携带着类型信息。例如:
1
2
3
4
var names = List<String>();
names.addAll(['Seth', 'Kathy', 'Lars']);
bool b = names is List<String>;
print('result:$b'); //true
- 相反,Java中的泛型使用擦除,也就是说Java在运行时删除泛型类型参数。在Java中,您可以测试对象是否为List,但您无法测试它是否为一个字符串列表(List
)。
限制参数类型
在使用泛型时,可以使用extends关键字来限制其参数类型:
1
2
3
4
5
6
7
8
9
10
11
12
class SomeBaseClass {
}
// 泛型,限制类型
class Foo<T extends SomeBaseClass> {
// Implementation goes here
String toString() => "Instace of 'Foo<$T>'";
}
// 继承
class Extender extends SomeBaseClass {
//do something
}
使用SomeBaseClass或其任何子类作为通用参数都是可以的,也可以不指定类型:
1
2
3
4
5
6
var someBaseClassFoo = Foo<SomeBaseClass>();
// 可以使用子类
var extenderFoo = Foo<Extender>();
// 也可以不指定泛型的类型
var foo = Foo();
print(foo);
使用泛型方法
Dart的泛型最初只支持对类使用。现在Dart的新语法已经支持在方法和函数上使用泛型。
1
2
3
4
5
6
7
8
9
10
// 泛型方法
T first<T>(List<T> ts) {
// Do some initial work or error checking, then...
// List中的参数类型是泛型
T tmp = ts[0];
// Do some additional checking or processing...
//返回一个泛型的方法
return tmp;
}
上边first(
- 在函数的返回类型
T
中。 - 在参数类型
List<T>
中。 - 在局部变量的类型
T tmp
中。