问题 如何确定类型参数的方差?


灵感来自 Scala中的共同和逆变的真实例子 我认为一个更好的问题是:

在设计库时,在确定类型参数是应该是协变还是逆变时,是否应该问自己一组特定的问题?或者你应该让一切都不变,然后根据需要改变?


7728
2018-03-11 23:34


起源



答案:


嗯,简单,有意义吗?想想利斯科夫的替代。

联合方差

如果 A <: B通过一个是否有意义 C[A] 哪里一个 C[B] 是期待?如果是这样,那就去吧 C[+T]。经典的例子是不可变的 List,哪里一个 List[A] 可以传递给任何期待的东西 List[B], 假设 A 是一个子类型 B

两个反例:

可变序列是不变的,因为否则可能会发生类型安全违规(事实上,Java的共变体) Array 很容易受到这些事情的影响,这就是为什么它在Scala中是不变的)。

不可变 Set 是不变的,即使它的方法与不可变的方法非常相似 Seq。不同之处在于 contains,在集合上键入和无类型(即,接受 Any)序列。因此,即使否则可能使其变为共变体,对特定方法的类型安全性的增加的期望导致对共方差的不变性的选择。

孔特拉方差

如果 A <: B通过一个是否有意义 C[B] 哪里一个 C[A] 是期待?如果是这样,那就去吧 C[-T]。经典的例子就是 Ordering。虽然一些不相关的技术问题阻止了 Ordering 从反对变异,任何可以订购超级类的东西都是直观的 A 也可以订购 A。它遵循 Ordering[B],命令所有类型的元素 B,超类型 A,可以传递给期待的东西 Ordering[A]

而斯卡拉的 Ordering 不是反变体, Scalaz订购 是预期的逆变型。 Scalaz的另一个例子就是它 等于 特征。

混合方差?

Scala中最明显的混合方差示例是 Function1 (和2,3等)。它在它接收的参数中是反变量的,并且在它返回的内容中是共变量。但请注意 Function1 是什么用于很多闭包,闭包在很多地方使用,这些地方通常是Java使用(或将使用)单抽象方法类的地方。

因此,如果您有SAM类适用的情况,那么这可能是混合反方差和协方差的一个地方。


16
2018-03-12 01:10