给定以下示例代码:
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]
^
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设置为逆变来完成它的工作。
我看不到一个可以通过编译而在运行时失败的案例。你觉得呢?编译器是不是误报了?
我想我们有
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,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.follow[String]( h0 )
但您的方差注释要求
gen[T0,R1]
对象可以替换gen[T0,R0]
。它们不能,编译器正确地调用了您。
这可能是一个很傻的问题,但我挠头了很久也弄不明白其中的区别。 我正在浏览scala泛型页面:https://docs.scala-lang.org/tour/generic-classes.html 注意:泛型类型的子类型是不变的。这意味着,如果我们有一个stack[Char]类型的字符堆栈,那么它就不能用作stack[Int]类型的整数堆栈。这是不合理的,因为它使我们能够将真整数输入到字符堆栈中
问题内容: Java中的协变返回类型是什么?在一般的面向对象编程中? 问题答案: 协变返回,意味着当一个方法被覆盖时,覆盖方法的返回类型被允许为覆盖方法的返回类型的子类型。 为了举例说明,通常情况是-声明为返回类型。你可以在自己的类中重写此方法,如下所示: 这样做的好处是,任何持有对MyFoo对象的显式引用的方法都将能够调用clone()并知道(无需强制转换)返回值是的实例。如果没有协变量返回类型
从Joshua Bloch的Effective Java中, > 数组与泛型类型有两个重要的区别。第一个数组是协变的。泛型是不变的。 协变简单地说,如果X是Y的子型,那么X[]也将是Y[]的子型。数组是协变的,因为字符串是对象的子类型,所以 不变简单地说,不管X是不是Y的子类型, 我的问题是为什么决定在Java中使数组是协变的?还有其他的SO帖子,比如为什么数组是不变的,但是列表是协变的?,但它们
问题内容: 摘自Joshua Bloch的Effective Java, 数组在两个重要方面不同于通用类型。第一数组是协变的。泛型是不变的。 协变量仅表示如果X是Y的子类型,则X []也将是Y []的子类型。数组是协变的,因为字符串是Object的子类型,所以 不变式仅表示X是否为Y的子类型, 问题答案: Java和C#的早期版本不包含泛型(又称参数多态性)。 在这种情况下,使数组不变会排除有用的
问题内容: 我了解协方差和逆方差。但是有一件小事我无法理解。在Coursera的“ Scala中的函数式编程”课程中,Martin Ordersky提到: 函数的参数类型是互变的,而返回类型是协变的 因此,例如在Java中,让extends出现。并让一个函数为: 我有函数调用为 所以基本上就是这样。根据Wiki,协方差是“从宽到窄转换”。在上面,我们正在从狗变成动物。所以论点类型不是协变而是协变吗
SBT将编译后的scala文件放在目标/scala文件夹中- 据我所知,类文件包含JVM字节码。它们与语言无关。 那么,文件夹使用语言名称的原因是什么?我希望Scala和Java的类字段都位于同一个目录中。