受到Real-world examples of co- and contravariance in Scala的启发,我认为一个更好的问题是:
在设计库时,在确定类型参数是应该是协变还是逆变时,是否应该问自己一组特定的问题?或者你应该让一切变得不变,然后根据需要改变吗?
答案 0 :(得分:16)
嗯,简单,它有意义吗?想想利斯科夫的替代。
如果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]
的东西。
虽然Scala的Ordering
不是反式变体,但Scalaz的Order符合预期。 Scalaz的另一个例子是它的Equal特征。
Scala中最明显的混合方差示例是Function1
(以及2,3等)。它在它接收的参数中是反变量的,并且在它返回的内容中是共变量。但请注意,Function1
是用于许多闭包的,并且闭包在很多地方使用,这些地方通常是Java使用(或将使用)单抽象方法类的地方。 p>
因此,如果你有SAM类适用的情况,那很可能是混合反方差和协方差的地方。