泛型
泛型即参数化类型,它是一个既常见又重要的编程语言特性。本文将举例说明泛型的优势和具体使用方法。
类型安全
泛型的优势之一是类型安全。
// ex611.dart
void main() {
var list = [];
list.add(1);
list.add('A');
print('$list ${list.runtimeType}'); // Output: [1, A] List<dynamic>
}
此例中list的类型为List<dynamic>,表示list可以包含任何类型的数据。如果将list声明为 List<int>将引起编译错误。
// ex611a.dart
void main() {
var list = <int>[];
list.add(1);
list.add('A');
// Error: The argument type 'String' can't be assigned to the parameter type 'int'.
}
减少代码重复
泛型的另一个优势是减少代码重复。实战中经常要将来自设备或网络的数据缓存起来。下面的代码创建一个用于缓存String数据的类。
// ex612.dart
class StringCache {
final String data;
StringCache(this.data);
}
使用相同的代码结构可为double、int及其它数据类型的数据创建对应的缓存类。例如:
// ex612a.dart
class DoubleCache {
final double data;
DoubleCache(this.data);
}
通过使用泛型技术我们只需要创建一个类,就可以 cover 此类应用场景。
// ex613.dart
class Cache<T> { // 1
final T data; // 2
Cache(this.data);
}
void main() {
var str = Cache('Dart'); // 3
var num = Cache(12); // 4
assert(str.data == 'Dart');
assert(num.data == 12);
}
- 泛型的类型参数
T写在一对尖括号(<>)中; - 字段
data的数据类型被声明为T; - 得益于 Dart 的自动类型推断,
Cache('Dart')即Cache<String>('Dart'),类型参数T将在编译时被替换为String; - 同上,
Cache(12)即Cache<int>(12)。
限制参数化类型
使用extends关键字让参数化类型为指定类型的子类型。
// ex614.dart
class Cache<T extends Object> {
final T data;
Cache(this.data);
}
void main() {
Cache(null);
// Error: The argument type 'Null' can't be assigned to the parameter type 'Object'.
}
此例中的T为 Object 的子类,它不能是 Null 类型。
泛型方法
参数化类型也可用在方法或函数里,语法是将类型参数连通一对尖括号,写在方法或函数名后面。
// ex615.dart
class Example {
static T max<T extends Comparable<T>>(T a, T b) => a.compareTo(b) > 0 ? a : b;
}
T min<T extends Comparable<T>>(T a, T b) => a.compareTo(b) < 0 ? a : b;
void main() {
print(Example.max(12, 34)); // Output: 34
print(min('apple', 'orange')); // Output: apple
}