Dart 和 Swift 的泛型有什么区别?

224 阅读3分钟

泛型(Generics)是一种在编程语言中用于创建可重用代码的机制。它允许我们定义类、接口和方法,可以使用不同类型的参数进行操作,从而提高代码的灵活性和复用性

Dart 和 Swift 的泛型在概念上是相似的,都是为了提高代码的复用性和类型安全性,但它们在实现细节、语法和特性上存在一些关键差异。以下是两者的主要区别总结:

1. 基本语法

Dart

  • 定义泛型类/方法:使用 <T> 语法,类型参数通常用 TKV 等表示。
    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 在运行时保留泛型类型信息,可通过 MirrorType 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

  • 泛型函数:通过 typedefFunction 类型定义,但灵活性较低。
    T identity<T>(T value) => value;
    

Swift

  • 泛型闭包:支持直接在闭包中使用泛型。
    let genericClosure: (Any) -> String = { value in
      return "\(value)"
    }
    

8. 核心差异总结

特性DartSwift
协变/逆变不支持(默认不型变)支持协变
类型擦除运行时擦除类型信息保留类型信息
多重约束通过 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 的泛型:更强大和灵活,支持协变、多重约束、泛型协议,默认保留类型信息,适合复杂场景。