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. |