我的理解是在以下情况下使用类型差异:
如果泛型类型G
具有类型参数T1
,它显示为G
方法的参数类型,则G
可以< T1
中的强>逆变。
如果G
的类型参数T2
显示为G
的方法(或ctor)的任何返回值的类型,那么G
可以在T2
中协变。
如果我在上面的句子中用替换 该怎么办?怎么办?是否有其他使用共同变体和反变体的情况?何时以及为什么要将您的类型变为共同变体和反变体?
答案 0 :(得分:3)
从规范引用,4.5方差注释:
方差注释指示参数化类型的实例如何变化 到子类型(§3.5.2)。 '+'方差表示协变依赖,' - ' 方差表示逆变依赖性,缺少方差指示 表示不变的依赖关系。 方差注释约束了带注释的类型变量的显示方式 在绑定类型参数的类型或类中。在类型定义中 类型T [tps] = S,或类型声明类型T [tps]&gt;:L&lt ;:U类型参数 标记为+'必须仅出现在协变位置,而标记的类型参数 ' - '必须只出现在逆变位置。
因此,默认情况下,类型参数被认为是不变的。您必须明确地将类型参数注释为co-or contravariant 如果你想使用它。此外,在完全没有使用的类型参数上使用方差注释是完全合法的(尽管他可能不那么有用)。 例如:
scala> class A[+T, -S] {def myMethod(s: String) = println(s)}
defined class A
scala> class A2[T] {def myMethod(t: T) = println(t)}
defined class A2
scala> class A3[-T] {def myMethod(t: T) = println(t)}
defined class A3
scala> val a1 = new A2[Any]
a1: A2[Any] = A2@1cd1cea
scala> val a2: A2[Int] = a1
:6: error: type mismatch;
found : A2[Any]
required: A2[Int]
val a2: A2[Int] = new A2[Any]
scala> val a3 = new A3[Any]
a3: A3[Any] = A3@875dee
scala> val a4: A3[Int] = a3
a5: A3[Int] = A3@875dee
A3类中的方差注释(在此示例中是逆变的)使得A3 [Any]被认为是A3 [Int]的子类型, 使从实例a4到a3的分配合法化。如果不使用方差注释,则会失败。
答案 1 :(得分:3)
事情并非那么简单。有时方差根本没有意义,所以你只需保持类不变。
另外,请注意方差在使用链中切换。例如:
class A[+T]
class B[-T] {
def f(x: A[T]) {}
}
class C[+T] {
def g(x: B[T]) {}
}
或者换句话说,这可以用几行来描述,这不是一件简单的事情。这就是为什么Scala强有力的方差实施是一个非常有用的东西的主要原因 - 现在,我有一半确信大多数使用Java中的差异的代码必须有微妙的错误。
答案 2 :(得分:1)
让我试一试这个老问题。协方差和逆变的一个用法是通过下限> :(协方差)和上限&lt; :(逆变)对Generic进行一些限制。用法可以在以下代码段中看到。它来自我自己的blog关于这个主题。
abstract class Animal (animalType:String)
class HasFourLegs(animalType:String) extends Animal(animalType){
def move=println(this+" walking on four legs")
}
class HasTwoLegs(animalType:String) extends Animal(animalType){
def move=println(this+" walking on Two legs")
}
case class Dog(animalType:String) extends HasFourLegs(animalType)
case class Ostrich(animalType:String) extends HasTwoLegs(animalType)
def moveOn4legs[T<:HasFourLegs](animal:T)= animal.move
val dog = Dog("dog")
val ostrich=Ostrich("ostrich")
moveOn4legs(dog)
/*
moveOn4legs(ostrich)
error: inferred type arguments [this.Ostrich] do not conform to method moveOn4legs's type parameter bounds [T <: this.HasFourLegs]
moveOn4legs(ostrich)
^
*/
println
class AnimalMovement [+T]{
def movement[U>:T](animal:U)=println(animal+" walking on Two legs!!!")
}
val moveLikeTwoLegs=new AnimalMovement[HasTwoLegs]()
moveLikeTwoLegs.movement(ostrich)
moveLikeTwoLegs.movement(dog)