泛型(Generics)是一种在编程语言中用于创建可重用代码的机制。它允许我们定义类、接口和方法,可以使用不同类型的参数进行操作,从而提高代码的灵活性和复用性
Dart 和 Swift 的泛型在概念上是相似的,都是为了提高代码的复用性和类型安全性,但它们在实现细节、语法和特性上存在一些关键差异。以下是两者的主要区别总结:
1. 基本语法
Dart
- 定义泛型类/方法:使用
<T>语法,类型参数通常用T、K、V等表示。class Box<T> { T value; Box(this.value); } - 调用泛型:在实例化或调用时指定具体类型。
Box<int> intBox = Box(10);
Swift
- 定义泛型类/方法:使用
<T>语法,支持更灵活的约束和关联类型。class Box<T> { var value: T init(_ value: T) { self.value = value } } - 调用泛型:与 Dart 类似。
let intBox = Box(10)
2. 类型约束(Type Constraints)
Dart
- 单继承约束:通过
extends指定类型必须是某个类的子类。class Box<T extends num> { // T 必须是 num 的子类型(如 int、double) T value; Box(this.value); } - 多重约束:不支持直接多重继承约束(如
T extends A & B),但可通过接口实现。class Box<T extends Comparable & Object> { // 不支持,需拆分 // ... }
Swift
- 多重约束:通过
where关键字实现复杂约束。func printIfComparable<T>(_ value: T) where T: Comparable, T: Equatable { // T 必须同时符合 Comparable 和 Equatable 协议 }
3. 协变与逆变(Covariance & Contraviance)
Dart
- 默认不型变(Invariant):泛型类型参数不支持协变或逆变。
List<Orange> oranges = [Orange()]; List<Fruit> fruits = oranges; // 编译错误!Dart 不支持协变 - 协变需显式声明:Dart 没有内置协变语法,需通过接口或类型擦除实现。
Swift
- 支持协变:通过
inout和协议修饰符(如SomeProtocol)实现协变。func acceptArray<T>(_ arr: [T]) where T: Fruit { let oranges: [Orange] = [Orange()] acceptArray(oranges) // 允许,Swift 支持协变 }
4. 类型擦除(Type Erasure)
Dart
- 运行时擦除类型信息:泛型的类型参数在运行时不可见,无法通过反射获取具体类型。
print(Box<int>().runtimeType); // 输出:Box (不包含类型参数信息)
Swift
- 保留泛型类型信息:Swift 在运行时保留泛型类型信息,可通过
Mirror或Type Erasure技巧操作。let box = Box<Int>(10) print(type(of: box)) // 输出:Box<Int>
5. 泛型协议(Generics in Protocols)
Dart
- 不支持泛型接口/协议:Dart 的
interface概念较弱,泛型约束需通过类继承实现。
Swift
- 泛型协议:支持通过
associatedtype定义关联类型。protocol Container { associatedtype Item mutating func push(_ item: Item) func pop() -> Item }
6. 默认类型参数(Default Type Parameters)
Dart
- 不支持默认类型参数:无法在泛型中指定默认类型。
// 错误!Dart 无法设置默认类型 class Box<T = int> { ... }
Swift
- 支持默认类型参数:
func printValue<T: CustomStringConvertible = String>(_ value: T) { print(value.description) }
7. 泛型函数与闭包
Dart
- 泛型函数:通过
typedef或Function类型定义,但灵活性较低。T identity<T>(T value) => value;
Swift
- 泛型闭包:支持直接在闭包中使用泛型。
let genericClosure: (Any) -> String = { value in return "\(value)" }
8. 核心差异总结
| 特性 | Dart | Swift |
|---|---|---|
| 协变/逆变 | 不支持(默认不型变) | 支持协变 |
| 类型擦除 | 运行时擦除类型信息 | 保留类型信息 |
| 多重约束 | 通过 extends 但不支持多条件 | 通过 where 支持多条件约束 |
| 泛型协议 | 不支持 | 支持 associatedtype |
| 默认类型参数 | 不支持 | 支持 |
| 泛型闭包 | 不直接支持 | 支持 |
示例对比
场景 1:协变列表
Dart
List<Orange> oranges = [Orange()];
List<Fruit> fruits = oranges; // 编译错误!Dart 不允许协变
Swift
var oranges: [Orange] = [Orange()]
var fruits: [Fruit] = oranges // 允许协变
场景 2:泛型协议
Dart
// 无法直接定义泛型接口,需通过类实现
abstract class Container<T> {
void add(T item);
}
Swift
protocol Container {
associatedtype Item
mutating func add(_ item: Item)
}
总结
- Dart 的泛型:更接近 Java/Kotlin 的实现,强调简单性和类型安全,但灵活性有限(如不支持协变、泛型协议)。
- Swift 的泛型:更强大和灵活,支持协变、多重约束、泛型协议,默认保留类型信息,适合复杂场景。