Scala方差:协变,不变和逆变
在这篇文章中,我们将讨论Scala Variance及其用例。
什么是方差?
方差定义参数化类型的继承关系。
差异全部与子类型有关。
请浏览下图以了解"什么是参数化类型"。
在此,T被称为"类型参数",而List [T]被称为泛型。
对于List [T],如果我们使用List [Int],List [AnyVal]等,则这些List [Int]和List [AnyVal]被称为"参数化类型"
方差定义了这些参数化类型之间的继承关系。
Scala中的差异优势
Scala Variance的主要优点是:
差异使Scala集合更具类型安全性。
差异使开发更加灵活。
Scala Variance为我们提供了开发可靠应用程序的技术。
Scala中的方差类型
Scala支持以下三种方差。
- 协变
- 不变的
- 逆变的
我们将在接下来的部分中详细讨论这三个差异。
Scala中的协变
如果" S"是" T"的子类型,则List [S]是List [T]的子类型。
双参数类型之间的这种继承关系被称为"共变"
Scala协方差语法:-为了表示两个参数化类型之间的协方差关系,Scala使用以下语法:前缀类型带" +"符号的参数定义Scala中的协方差。
T是类型参数," +"符号定义Scala协方差。
注意:-为简单起见,我在这里使用"列表"。
但是,它可以是任何有效的Scala类型,例如Set [+ T],Ordered [+ T]等。
示例:-编写一个Scala程序来演示Scala协变量子类型技术。
class Animal[+T](val animial:T)
class Dog
class Puppy extends Dog
class AnimalCarer(val dog:Animal[Dog])
object ScalaCovarianceTest{
def main(args: Array[String]) {
val puppy = new Puppy
val dog = new Dog
val puppyAnimal:Animal[Puppy] = new Animal[Puppy](puppy)
val dogAnimal:Animal[Dog] = new Animal[Dog](dog)
val dogCarer = new AnimalCarer(dogAnimal)
val puppyCarer = new AnimalCarer(puppyAnimal)
println("Done.")
}
}
注意:-由于Animal类是通过使用方差注释(即" + T")定义的,因此我们可以传递dogAnimal或者其子类型puppyAnimal来创建AnimalCarer对象。
如果我们在动物类定义中删除差异注释,就像如下图所示:
class Animal[T](val animial:T) //Remaining code is same as above.
它不会编译。
我们将收到以下编译错误消息:
Type mismatch, expected: Animal[Dog], found: Animal[Puppy]
为了解决这类问题,我们应该使用Scala协方差。
按照这个例子,我们可以说以下斯卡拉协方差:
"由于小狗是狗的亚型,所以动物[小狗]是动物[狗]的亚型。
我们可以在需要Animal [Dog]的地方使用Animal [Puppy]。
"这就是Scala协方差。
Scala中的变量
如果" S"是" T"的子类型,则List [T]是List [S]的子类型。
两种参数化类型之间的这种继承关系称为" Contravariant"
Scala变量语法:为了表示两个参数化类型之间的变量关系,Scala使用以下语法:前缀类型参数中带有"-"符号的参数定义了Scala中的变量。
示例:-编写一个Scala程序来演示Scala可变子类型技术。
abstract class Type [-T]{
def typeName : Unit
}
class SuperType extends Type[AnyVal]{
override def typeName: Unit = {
println("SuperType")
}
}
class SubType extends Type[Int]{
override def typeName: Unit = {
println("SubType")
}
}
class TypeCarer{
def display(t: Type[Int]){
t.typeName
}
}
object ScalaContravarianceTest {
def main(args: Array[String]) {
val superType = new SuperType
val subType = new SubType
val typeCarer = new TypeCarer
typeCarer.display(subType)
typeCarer.display(superType)
}
}
注意:-当我们在Type [-T]中定义Contravariance时,它工作良好。
TypeCarer.display()是使用Type Int定义的,但仍可以接受Type [AnyVal],因为Scala的Contravariance子类型化。
如果我们去掉" - "中键入比如定义"类型[T]",那么我们将得到编译错误。
Scala中的不变式
如果"S"是"T"的子类型列表然后[S]和List [T]不具有继承关系或者子类型。
这意味着两者无关。
两种参数化类型之间的这种关系称为"不变或者无变量"
在Scala中,默认情况下,泛型类型具有Non-Variant关系。
如果我们定义参数化类型,而无需使用"+"或者‘ - ’符号,则他们被称为不变。
什么是Scala中的方差注释?
差异注释表示在类型参数之前定义" +"或者"-"。
例如:+ T和–T在Scala中称为方差注释。
Scala方差摘要
在本节中,我们将总结在以上各节中讨论过的有关Scala方差类型的所有3个概念。
| Scala Variance Type | Syntax | Description |
|---|---|---|
| Covariant | [+T] | If S is subtype of T, then List[S] is also subtype of List[T] |
| Contravariant | [-T] | If S is subtype of T, then List[T] is also subtype of List[S] |
| Invariant | [T] | If S is subtype of T, then List[S] and List[T] are unrelated. |

