在 Dart 中,泛型(Generics)是一种强大的编程特性,它允许你编写可以处理多种数据类型的代码,同时保持类型安全。
当没有泛型的时候
Dart
// 只能存储字符串的列表
class StringList {
List<String> items = [];
void add(String item) {
items.add(item);
}
String get(int index) {
return items[index];
}
}
// 只能存储整数的列表
class IntList {
List<int> items = [];
void add(int item) {
items.add(item);
}
int get(int index) {
return items[index];
}
}
// 需要为每种类型创建单独的类,代码重复!
使用泛型解决代码重复问题
Dart
// 通用的列表类,可以存储任何类型
class GenericList<T> {
List<T> items = [];
void add(T item) {
items.add(item);
}
T get(int index) {
return items[index];
}
}
void main() {
// 存储字符串
var stringList = GenericList<String>();
stringList.add("Hello");
stringList.add("World");
print(stringList.get(0)); // 类型安全:知道返回的是String
// 存储整数
var intList = GenericList<int>();
intList.add(1);
intList.add(2);
print(intList.get(0)); // 类型安全:知道返回的是int
}
语法理解
Dart
// T 是类型参数,可以是任何标识符
class ClassName<T> {
T value;
ClassName(this.value);
T getValue() {
return value;
}
}
// 多个类型参数
class Pair<K, V> {
K key;
V value;
Pair(this.key, this.value);
}
泛型可以用于集合中List,Set和Map类型的参数化。对于List或Set,只需要在声明语句前添加类型前缀;对于Map,则需要在声明语句前添加<keyType,valueType>类型前缀。
1.List不用泛型
Dart
void main() {
// 创建一个列表,但不指定类型
List names = ['Alice', 'Bob', 'Charlie']; // 什么都能放
names.add('David'); // ✅ 可以加字符串
names.add(123); // ✅ 也可以加数字(但这样容易出错!)
names.add(true); // ✅ 还可以加布尔值
// 使用时不知道是什么类型,容易出错
String firstPerson = names[0]; // ❌ 运行时可能出错,因为不知道names[0]是不是字符串
print(firstPerson.toUpperCase()); // 如果names[0]是数字,这里就会崩溃!
}
List使用泛型
Dart
void main() {
// 创建一个只能放字符串的列表
List<String> names = ['Alice', 'Bob', 'Charlie'];
names.add('David'); // ✅ 可以加字符串
// names.add(123); // ❌ 编译时就报错!不能加数字
// names.add(true); // ❌ 编译时就报错!不能加布尔值
// 使用时很安全,知道一定是字符串
String firstPerson = names[0]; // ✅ 安全,知道肯定是字符串
print(firstPerson.toUpperCase()); // ✅ 不会出错
}
2.Map不使用泛型
Dart
void main() {
// 创建一个Map,但不指定键值类型
Map student = {
'name': 'Alice',
'age': 20,
'score': 95.5
};
student['height'] = 165; // ✅ 可以添加
student[123] = 'test'; // ✅ 键可以是数字(混乱!)
student['name'] = 999; // ✅ 把名字改成数字(不对!)
// 使用时很困惑
String name = student['name']; // ❌ 可能出错,因为name可能不是字符串
int age = student['age']; // ❌ 可能出错
}
Map使用泛型
Dart
void main() {
// 创建一个Map,键必须是字符串,值可以是任意类型
Map<String, dynamic> student = {
'name': 'Alice', // 值:字符串
'age': 20, // 值:数字
'score': 95.5 // 值:小数
};
student['height'] = 165; // ✅ 可以添加
// student[123] = 'test'; // ❌ 编译错误!键必须是字符串
// student['name'] = 999; // ❌ 编译错误!名字应该是字符串
// 使用时很清楚
String name = student['name']; // ✅ 安全
int age = student['age']; // ✅ 安全
}