标签:
Scala的类型系统必须同时解释类层次和多态性。类层次结构可以表达子类关系。在混合OO和多态性时,一个核心问题是:如果T’是T一个子类,Container[T’]应该被看做是Container[T]的子类吗?变性(Variance)注解允许你表达类层次结构和多态类型之间的关系:
含义 | Scala 标记 | |
协变covariant | C[T’]是 C[T] 的子类 | [+T] |
逆变contravariant | C[T] 是 C[T’]的子类 | [-T] |
不变invariant | C[T] 和 C[T’]无关 | [T] |
子类型关系的真正含义:对一个给定的类型T,如果T’是其子类型,你能替换它吗?
scala> class Covariant[+A] defined class Covariant scala> val cv: Covariant[AnyRef] = new Covariant[String] cv: Covariant[AnyRef] = Covariant@4035acf6 scala> val cv: Covariant[String] = new Covariant[AnyRef] <console>:6: error: type mismatch; found : Covariant[AnyRef] required: Covariant[String] val cv: Covariant[String] = new Covariant[AnyRef] ^
scala> class Contravariant[-A] defined class Contravariant scala> val cv: Contravariant[String] = new Contravariant[AnyRef] cv: Contravariant[AnyRef] = Contravariant@49fa7ba scala> val fail: Contravariant[AnyRef] = new Contravariant[String] <console>:6: error: type mismatch; found : Contravariant[String] required: Contravariant[AnyRef] val fail: Contravariant[AnyRef] = new Contravariant[String] ^
逆变似乎很奇怪。什么时候才会用到它呢?令人惊讶的是,函数特质的定义就使用了它!
trait Function1 [-T1, +R] extends AnyRef
如果你仔细从替换的角度思考一下,会发现它是非常合理的。让我们先定义一个简单的类层次结构:
scala> class Animal { val sound = "rustle" } defined class Animal scala> class Bird extends Animal { override val sound = "call" } defined class Bird scala> class Chicken extends Bird { override val sound = "cluck" } defined class Chicken
假设你需要一个以Bird
为参数的函数:
scala> val getTweet: (Bird => String) = // TODO
标准动物库有一个函数满足了你的需求,但它的参数是Animal
。在大多数情况下,如果你说“我需要一个___,我有一个___的子类”是可以的。但是,在函数参数这里是逆变的。如果你需要一个接受参数类型Bird
的函数变量,但却将这个变量指向了接受参数类型为Chicken
的函数,那么给它传入一个Duck
时就会出错。然而,如果将该变量指向一个接受参数类型为Animal
的函数就不会有这种问题:
scala> val getTweet: (Bird => String) = ((a: Animal) => a.sound ) getTweet: Bird => String = <function1>
注意:这里给Bird传的是超类,但是最终getTweet的类型还是Bird的,要是Bird中没有sound方法,就调用超类的,要是Bird中有sound方法,就调用Bird的。 也就是说,在给函数传实际的参数时,可以传超类的,也可以传子类的。
函数的返回值类型是协变的。如果你需要一个返回Bird
的函数,但指向的函数返回类型是Chicken
,这当然是可以的。
scala> val hatch: (() => Bird) = (() => new Chicken ) hatch: () => Bird = <function0>
标签:
原文地址:http://www.cnblogs.com/wlwgcdxc/p/4589015.html