第一章:泛型协变逆变限制
在面向对象编程中,泛型的协变(Covariance)与逆变(Contravariance)是类型系统的重要特性,用于描述子类型关系在复杂类型构造中的传递方式。然而,并非所有语言或上下文都允许任意形式的协变或逆变,这些使用场景往往受到严格的限制。
协变的基本概念
协变允许将一个泛型类型的子类型视为其目标类型的子类型。例如,在支持协变的类型系统中,若 `Cat` 是 `Animal` 的子类,则 `List` 可被视为 `List` 的子类型。这种转换仅在类型参数仅用于输出位置时安全。
逆变的应用场景
逆变则相反,它允许父类型在输入位置上替代子类型。典型应用场景出现在函数式接口中,如比较器或处理器。例如,一个接受 `Animal` 的比较器可以安全地用于 `Cat` 列表的排序。
语言层面的限制示例
以 C# 为例,只有在接口或委托中显式使用
out 或
in 关键字时,才能启用协变或逆变:
// 协变:T 仅用于输出
public interface IProducer<out T>
{
T Produce();
}
// 逆变:T 仅用于输入
public interface IConsumer<in T>
{
void Consume(T item);
}
上述代码中,
out T 表示该类型参数只能作为方法返回值(输出),从而保证协变的安全性;
in T 则限制其仅能作为参数传入,确保逆变的类型安全。
- 协变适用于只读数据结构,如集合枚举器
- 逆变适用于只写操作,如事件处理器注册
- 可变(不变)是默认行为,兼顾读写安全性
| 类型变换 | 关键字 | 使用位置 |
|---|
| 协变 | out | 返回值 |
| 逆变 | in | 参数输入 |
第二章:协变与逆变的理论基础
2.1 协变与逆变的概念起源与数学背景
协变(Covariance)与逆变(Contravariance)源于类型系统中对子类型关系在复杂类型构造下的保持方式,其理论根基可追溯至范畴论中的函子映射。
数学原型:函数类型的变型规则
在类型构造中,若 `A ≼ B` 表示 A 是 B 的子类型,则函数类型 `(B → T)` 是 `(A → T)` 的子类型——参数类型逆向继承,称为逆变;而返回类型则协变保持:`(S → A) ≼ (S → B)` 当 `A ≼ B`。
- 协变:保持子类型方向,如列表类型 `List ≼ List