Dart 面向对象之泛型
Dart 中的集合(List、Map 等)可以包含多种类型的值,如果我们想强制规定集合中只包含一种类型的值,可以使用泛型来解决这个问题。
只包含一种类型的集合一般被称作类型安全集合,类型安全是一种编程功能,可确保某个内存块只能包含特定数据类型的数据。
泛型的语法
泛型的语法非常简单,使用 <>
标识符即可声明泛型,例如声明一个只包含 String
的 List
:
实例化构造函数的形式:
var names = List<String>();
var pages = Map<String, String>();
声明字面量的形式:
var names = <String>[];
var pages = <String, String>{};
泛型的优点
类型安全
泛型是类型安全的,因此我们在使用时必须使用指定的数据类型,否则编辑器将会提示错误,代码在运行后也会报错,例如:
void main() {
var names = <String>[];
names.addAll(['Adele', 'Sia', 'Enya']);
names.add('Beyonce');
print(names);// output: [Adele, Sia, Enya, Beyonce]
names.add(123);// Try changing the type of the parameter, or casting the argument to 'String'.
}
上面的代码中,names
变量使用了泛型,规定它是一个只包含 String
成员的 List
,当往 names
中追加 int
类型的成员时,编辑器会直接提示错误,并且运行后会出错。
减少重复代码
泛型可以在多种类型之间定义同一个实现,同时还可以继续使用检查模式和静态分析工具提供的代码分析功能。
例如,我们创建了一个缓存 Object
的接口:
abstract class ObjectCache {
Object getByKey(String key);
setByKey(String key, Object value);
}
接着再创建一个缓存 String
的接口:
abstract class StringCache {
String getByKey(String key);
setByKey(String key, String value);
}
如果后面需要创建一个缓存 int
、Map
等等类型的接口,则还需要重复以上代码,非常麻烦。此时使用泛型就可以解决这个代码重复的问题,例如:
abstract class StringCache<T> {
T getByKey(String key);
setByKey(String key, T value);
}
上面的代码中,T
是一个类型的占位符,你也可以将 T
换成其他字母。如果开发者需要调用该接口,则必须指定某个具体类型。
泛型的使用
限制泛型类型
当我们需要限制泛型的具体类型时,可以使用 extends
关键字进行约束:
class Human {
}
class Man extends Human {
}
class Person<T extends Human> {
toString() => 'Instance of Human<$T>';
}
void main() {
final leo = Person<Man>();
final sia = Person<Human>();
final bob = Person();
print(leo);// output: Instance of Human<Man>
print(sia);// output: Instance of Human<Human>
print(bob);// output: Instance of Human<Human>
}
上面的代码中,泛型参数被约束为 Human
类或 Human
子类。
使用泛型函数
Dart 1.21 之后的版本开始支持泛型函数,用法如下:
T first<T>(List<T> lists) {
T tmp = lists[0];
return tmp;
}
void main() {
final str = first<String>(['foo']);
print(str);// output: foo
}
上面的代码中,泛型函数 first<T>
的泛型参数 T
可以在如下地方使用:
-
函数的返回值类型
T first
-
参数的类型
List<T>
-
局部变量的类型
T tmp
发布评论
还没有评论,快来抢沙发吧!