泛型约束
本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 67 课,共 110 课。
有时,你需要让泛型具备某些能力。例如,如果你想比较项目或访问特定属性,不受限制的 T 并不能保证这些功能存在。泛型约束可以将类型参数限制为特定类型或其子类。
使用 extends 关键字来限制类型参数:
class NumberBox<T extends num> {
T value;
NumberBox(this.value);
T doubled() => (value * 2) as T;
}
void main() {
var intBox = NumberBox<int>(5);
var doubleBox = NumberBox<double>(3.5);
print(intBox.doubled()); // 10
print(doubleBox.doubled()); // 7.0
// var stringBox = NumberBox<String>('hi'); // 错误!
}因为 T extends num,编译器知道 value 支持乘法等数值运算。没有这个约束,调用 value * 2 就会失败。
约束也适用于你自己的类层次结构:
abstract class Animal {
String get name;
}
class Dog extends Animal {
String get name => 'Dog';
}
class Shelter<T extends Animal> {
List<T> animals = [];
void add(T animal) => animals.add(animal);
void printNames() {
for (var animal in animals) {
print(animal.name); // 安全:T 保证 'name' 存在
}
}
}泛型约束结合了泛型的灵活性,同时让你确定自己的类型支持哪些操作,从而保证安全性。
挑战
简单我们来构建一个只能处理数值类型的统计计算器吧!你将创建一个带约束的泛型类,确保它只能用于数字,这样就能安全地对存储的值执行数学运算。
你将把代码分成两个文件:
stats.dart:创建一个泛型类Stats<T extends num>,用于管理数值列表:- 一个名为
values的List<T>,用于存储数字 - 一个使用给定值初始化列表的构造函数
- 一个
sum()方法,以num类型返回所有值的总和 - 一个
min()方法,以T类型返回最小值 - 一个
max()方法,以T类型返回最大值 - 一个
printStats()方法,以格式化的方式显示统计数据
- 一个名为
main.dart:导入你的统计文件,并使用不同的数值类型演示这个带约束的泛型类:- 创建一个值为
[10, 25, 5, 30, 15]的Stats<int>,并调用printStats() - 打印一个空行
- 创建一个值为
[3.5, 1.2, 4.8, 2.1]的Stats<double>,并调用printStats()
- 创建一个值为
printStats() 方法应输出三行,分别显示总和、最小值和最大值。由于 T extends num,你可以安全地对这些值使用比较运算符和算术运算。如果泛型类型没有约束,就无法进行这些操作。
预期输出:
Sum: 85
Min: 5
Max: 30
Sum: 11.6
Min: 1.2
Max: 4.8亲手试试
import 'stats.dart';
void main() {
// TODO: 创建一个 Stats<int>,值为 [10, 25, 5, 30, 15]
// 并调用 printStats()
// TODO: 输出一个空行
// TODO: 创建一个 Stats<double>,值为 [3.5, 1.2, 4.8, 2.1]
// 并调用 printStats()
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Dart 在线编译器