给出以下示例代码:
trait Gen[T, +R] {
def follow[K](gen: Gen[R, K]): Gen[T, K]
def i: T
def j: R
}
case class GenImpl[T, R](i: T, j: R) extends Gen[T, R] {
override def follow[K](gen: Gen[R, K]): Gen[T, K] = {
GenImpl[T, K](this.i, gen.j)
}
}
编译器将给出以下错误:
Error:(9, 17) covariant type R occurs in invariant position in type Gen[R,K] of value gen
def follow[K](gen: Gen[R, K]): Gen[T, K]
^
但是,此代码在运行时可能无法通过类型验证失败。 R的协变仅仅意味着:
R1 <: R, R2 <: R
然后:
Gen[T, R1] <:< Gen[T, R]
因此Gen [R,K]可以是Gen [T,R]和Gen [T,R1]的.follow()的参数。但是Gen [R1,K]只能是Gen [T,R1]的.follow()的参数,如果应用于Gen [T,R2]或Gen [T,R],它将触发编译错误。没有必要将Gen [R / R1,K]中的R或R1设置成逆变来完成它的工作。
我看不到可以通过编译并在运行时失败的情况。你怎么看?编译器是否会引发误报?
答案 0 :(得分:2)
假设我们有
class R0
class R1 extends R0
class T0
然后Gen[T0, R0]
的任何实例都必须提供以下服务:
def follow[K](gen : Gen[R0, K]) : Gen[T0,K]
方差注释声称Gen[T0, R1] <:< Gen[T0, R0]
。所以它必须是可替代的并提供相同的服务。但是Gen[T0, R1]
实际上提供了以下服务:
def follow[K](gen: Gen[R1, K]) : Gen[T0,K]
假设我有这样的代码:
def doFollow[K]( g : Gen[T0, R0], h : Gen[R0, K] ) : Gen[T0,K] = {
g.follow( h )
}
冷却。让我们假设我有一些实例,但是:
val g0 : Gen[T0, R0] = ???
val h0 : Gen[R0, String] = ???
val g1 : Gen[T0, R1] = ???
我打电话给doFollow[String]( g0 , h0 )
,一切都很好,我得到了一个结果。
g1
可以替代g0
。所以现在我尝试doFollow[String]( g1 , h0 )
。哎呀。然后我必须在函数体中执行
g1.follow[String]( h0 )
但g1
只知道如何关注Gen[R1, String]
。 h0
是Gen[R0, String]
。由于第一个参数被声明为不变(它必须是逆变的),所以Gen[R0, String] <:< Gen[R1, String]
不是真的。因此h0
不是g1
关注方法的可接受参数,而g0
跟随方法是可接受的参数。 g1
类型Gen[T0, R1]
的内容实际上不能替代g0
类型Gen[T0, R0]
的内容。
但您的方差注释要求Gen[T0, R1]
对象可以替代Gen[T0, R0]
s。他们不能,编译器正确地打电话给你。