Scala型变:不变、协变及逆变

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yiifaa/article/details/82258790

Scala在高阶类型的使用中,有三种变化,分别是顺变、协变及逆变,下面详细讲讲它们的含义与应用。

1. 高阶类型

高阶类型是接受其他参数用来构造新类型的,所以又称为“类型构造器”,用type关键字来定义:

//   定义高阶类型
type Foo[T] = Function0[T]
//   声明高阶类型变量
val foo: Foo[Int] = () => 1
//  输出1
println(foo())

高阶类型一个重要特点是,在参数化之前,它不是一个完整的类型,当然也就无法实例化了。

2. 不变

不变是指高阶类型的参数不能改变,所以,这当然是满足型变的,完全合法,如下:

val ln: List[String] = List("yiifaa")
# 参数一致,赋值显然是合法的
val l: List[String] = ln

3. 协变

协变是指把类型参数转换为参数的父类,创建方法是类型参数前加个“+”号,无需额外操作,如下:

case class Person[+T](username: T)
//  声明类型变量
val yiifaa: Person[String] = Person("yiifaa")
val yiifee: Person[Any] = yiifaa

如果不加“+”号会怎样?那就会产生类型不匹配错误,不能适应协变,只能“不变”了。

4. 逆变

逆变是相对于协变而言的,就是把类型参数转换为参数的子类,创建方法是在类型参数前加个“-”。将父类转换为子类是存在风险的,所以还需要添加转换函数,如下:

class Person[-T](username: T) {
  // 逆变时参数要放在函数上
  def apply(username: T): Person[String] = new Person(username)
}
val yiifee: Person[Any] = new Person("yiifaa")
//  逆变发生了
val yiifaa: Person[String] = yiifee

逆变主要应用于Function对象,其他地方较少。

总结

所有的类型编程都必须要在编译时确定是否合法,因为类型信息只有在编译时才是可知的(编译后会丢失),最后它们的关系图如下。不变、协变及逆变

猜你喜欢

转载自blog.csdn.net/yiifaa/article/details/82258790