目录
泛型(Generics)使用<...>来定义。
按照惯例,Dart2中使用E、T、K和V声明类型变量。比如: List<E>等等。
-
为什么使用泛型?
1. 指定泛型类型,可以是代码更安全,更易解读;
2. 使用泛型还可以避免代码重复。
// 官网代码
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);
}
main(List<String> args) {
// 指定String类型,只能添加String到list, 添加其他类型会报错
List<String> strList = List<String>();
strList.add("a");
strList.add(1); // 类型错误
}
-
用于集合类型
泛型可以用于List和Map的直接参数化,也可以通过构造函数参数化。
Dart2泛型类型被具体化了,这意味着它们在运行时携带着自己的类型信息。
main(List<String> args) {
// 直接参数化
var animals = <String>["cat", "dog"];
var animalMap = <String, String>{
"cat": "tom",
"dog": "jerry"
};
// 使用构造函数参数化
var animalList = List<String>();
var animalMap2 = Map<String, String>();
animalList.addAll(['bird', 'dog']);
// 转换成set时,需要指定类型
var animalSet = Set<String>.from(animalList);
// 可以直接判定类型
print(animalList is List<String>); // true
}
-
限制泛型参数类型
当实现一个泛型时,如果需要限制它参数的类型,可以使用extends
关键字。
下面是官网实例。
// 限制T必须是SomeBaseClass或者它的后台
class Foo<T extends SomeBaseClass> {...}
class Extender extends SomeBaseClass {...}
void main() {
// 直接使用SomeBaseClass或者它的后台Extender都是可以的
var someBaseClassFoo = new Foo<SomeBaseClass>();
var extenderFoo = new Foo<Extender>();
// 也可以什么参数也不指定
var foo = new Foo();
// 指定任何非SomeBaseClass类型,会报warn,在检查模式下,报运行时错误。
// var objectFoo = new Foo<Object>();
}