Scala中的协方差和协方差 [英] Contravariance and covariance in Scala

查看:59
本文介绍了Scala中的协方差和协方差的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

abstract class Bhanu[-A] { val m:List[A] }  

给予

error: contravariant type A occurs in covariant position in type => List[A] of value m
       abstract class Bhanu[-A] { val m:List[A] }

abstract class Bhanu[+A] { val m:List[A] }

给予

defined class Bhanu

对于为什么它因逆方差而失败而对于协方差却成功的原因,我无法全神贯注.

I am not able to wrap my head around this concept as to why it fails for contravariance whereas it succeeds for covariance.

第二(从其他示例中)

该陈述的确切含义是什么?

What does the statement exactly mean?

Function1[Sport,Int] <: Function1[Tennis,Int] since Tennis <: Sport

对我来说似乎违反直觉,不是吗?

It seems counter-intuitive to me, Shouldn't it be the following?

Function1[Tennis,Int] <: Function1[Sport,Int] since Tennis <: Sport

推荐答案

让我们看一下您提到的第一个示例.考虑我们有:

Let's look on the first example you mentioned. Consider we have:

class Fruit
class Apple extends Fruit
class Banana extends Fruit

class Bhanu[-A](val m: List[A]) // abstract removed for simplicity

由于 Bhanu Bhanu [Fruit]< ;: Bhanu [Apple] 相反,所以您可以执行以下操作:

Since Bhanu is contravatiant Bhanu[Fruit] <: Bhanu[Apple] so you can do the following:

val listOfApples = new List[Apple](...)
val listOfFruits = listOfApples // Since Lists are covariant in Scala 
val a: Bhanu[Fruit] = new Bhanu[Fruit](listOfFruits)
val b: Bhanu[Banana] = a // Since we assume Bhanu is contravariant
val listOfBananas: List[Banana] = b.m
val banana: Banana = listOfBananas(0) // TYPE ERROR! Here object of type Banana is initialized 
                                      // with object of type Apple

因此,Scala编译器通过限制在协变位置使用协变类型参数来保护我们免受此类错误的侵害.

So Scala compiler protects us from such errors by restriction to use contravariant type parameters in covariant position.

对于第二个问题,让我们也看一下示例.考虑我们有功能:

For your second question let's also look at the example. Consider we have function:

val func1: Function1[Tennis,Int] = ...

如果 Function1 [Tennis,Int]< ;: Function1 [Sport,Int] ,其中 Tennis< ;: Sport 如您所建议,那么我们可以执行以下操作:

If Function1[Tennis,Int] <: Function1[Sport,Int] where Tennis <: Sport as you proposed than we can do the following:

val func2: Function1[Sport,Int] = func1
val result: Int = func2(new Swimming(...)) // TYPE ERROR! Since func1 has argument 
                                           // of type Tennis.

但是,如果我们使 Function1 的参数相反,则 Function1 [Sport,Int]< ;: Function1 [Tennis,Int] 其中, Tennis< ;:运动比:

But if we make Function1 contravariant in its argument so Function1[Sport,Int] <: Function1[Tennis,Int] where Tennis <: Sport than:

val func1: Function1[Tennis,Int] = ...
val func2: Function1[Sport,Int] = func1 // COMPILE TIME ERROR!

对于相反的情况,一切都很好:

and everything is fine for the reverse case:

val func1: Function1[Sport,Int] = ...
val func2: Function1[Tennis,Int] = func1 // OK!
val result1: Int = func1(new Tennis(...)) // OK!
val result2: Int = func2(new Tennis(...)) // OK!

函数的参数类型必须是协变的,而结果类型必须是协变的:

Functions must be contravariant in their argument type and covariant in result type:

trait Function1[-T, +U] {
  def apply(x: T): U
}

这篇关于Scala中的协方差和协方差的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆