美文网首页IT@程序员猿媛
Scala中的协变与逆变

Scala中的协变与逆变

作者: 叫我不矜持 | 来源:发表于2019-06-09 20:46 被阅读0次

协变与逆变的概念

对于一个带类型参数的类型,比如 List[T],如果对A及其子类型B,满足 List[B]也符合 List[A]的子类型,那么就称为covariance(协变),如果 List[A]是 List[B]的子类型,即与原来的父子关系正相反,则称为contravariance(逆变)。

协变:

 _____               _____________ 
|     |             |             |
|  A  |             |  List[ A ]  |
|_____|             |_____________|
   ^                       ^ 
   |                       | 
 _____               _____________ 
|     |             |             |
|  B  |             |  List[ B ]  |
|_____|             |_____________|

逆变:

 _____               _____________ 
|     |             |             |
|  A  |             |  List[ B ]  |
|_____|             |_____________|
   ^                       ^ 
   |                       | 
 _____               _____________ 
|     |             |             |
|  B  |             |  List[ A ]  |
|_____|             |_____________|  

如果一个类型支持协变或逆变,则称这个类型为variance(翻译为可变的或变型),否则称为invariant(不可变的)

语法

在Java里,泛型类型都是invariant,比如 List<String> 并不是 List<Object> 的子类型。Java并不支持声明点变型(declaration-site variance,即在定义一个类型时声明它为可变型,也称definition-site),而scala支持,可以在定义类型时声明(用加号表示为协变,减号表示逆变),如:

在类型定义时(declaration-site)声明为协变
trait List[+T] 

这样会把List[String]作为List[Any]的子类型。

不过Java支持使用点变型(use-site variance),所谓“使用点“,也就是在声明变量时:

List<? extends Object> list = new ArrayList<String>();

scala为了兼容java泛型通配符的形式,引入存在类型(existential type,后边再讲)时,也支持了使用点变型(use-site variance)

scala> val a : List[_ <: Any] = List[String]("A")
a: List[_] = List(A)

协变不可被继承

要注意variance并不会被继承,父类声明为variance,子类如果想要保持,仍需要声明:

scala> trait A[+T]

scala> class C[T] extends A[T]  // C是invariant的

scala> class X; class Y extends X;

scala> val t:C[X] = new C[Y]
<console>:11: error: type mismatch; 
 found   : C[Y]
 required: C[X]
Note: Y <: X, but class C is invariant in type T.
You may wish to define T as +T instead. (SLS 4.5)

上面的例子可以看到,如果想实现协变必须也对C声明为协变的才行:

scala> class C[+T] extends A[T]

scala> val t:C[X] = new C[Y]
t: C[X] = C@6a079142

相关文章

  • Scala教程之:深入理解协变和逆变

    在之前的文章中我们简单的介绍过scala中的协变和逆变,我们使用+ 来表示协变类型;使用-表示逆变类型;非转化类型...

  • Scala 通俗易懂 ---- 协变、逆变、不变

    协变、逆变、不变 Scala 语言中协变、逆变、不变是指拥有泛型的类型,在声明和赋值时的对应关系 协变:声明时泛型...

  • Typescript 中的协变和逆变

    Typescript的协变和逆变和C# Scala中的类似,但是Typescript的会自动算出来接口属于协变还是...

  • Scala 类型系统(1)

    协变逆变引入原因 协变和逆变主要是用来解决参数化类型的泛化问题。我的理解是解决Scala高阶函数参数引入。 定义协...

  • Scala中的协变与逆变

    什么是协变和逆变 给出Student和Person两个类,其中Student为Person的子类,对于协变来说Li...

  • Scala中的协变与逆变

    协变与逆变的概念 对于一个带类型参数的类型,比如 List[T],如果对A及其子类型B,满足 List[B]也符合...

  • JAVA泛型与类型安全

    1. 基础泛型 2. 协变与逆变与不变 协变 简单来说即: Java中的数组是协变的 逆变与协变相对,逆转了类型关...

  • Kotlin 泛型协变与逆变的理解

    协变与逆变定义 逆变与协变用来描述类型转换后的继承关系 协变:如果 A 是 B 的子类型,并且Generic 也...

  • 泛型编程中的型变

    在泛型编程中,经常会提到型变。型变分为两种:协变与逆变。协变covariant表示与泛型参数T的变化相同,而逆变c...

  • Java协变和逆变

    泛型的协变与逆变 协变与逆变用来描述类型转换(type transformation)后的继承关系,其定义如下:如...

网友评论

    本文标题:Scala中的协变与逆变

    本文链接:https://www.haomeiwen.com/subject/rhxoxctx.html