How to check covariant and contravariant position of an element in the function?
这是我阅读的有关scala中的逆变和协方差的文章之一的代码片段。 但是,我无法理解scala编译器抛出的错误消息"错误:协变类型A出现在值pet2的类型A中的逆变位置
我对这段代码片段的理解是,Pets是协变的并且接受A的子类型的对象。但是,函数add仅接受A类型的参数.Being covariant意味着Pets可以获取A类及其子类型的参数。 那怎么会抛出错误呢。 从哪里出现逆变问题。
对上述错误消息的任何解释都将非常有用。 谢谢
TL; DR:
您的
您的
唯一剩下的可能性是:
举例说明:协方差与逆差:
我将利用这个机会提出一个改进的,显着的更多
这部漫画的严谨版本。它是协方差和逆变的一个例证
具有子类型和声明 - 站点方差注释的编程语言的概念
(显然,即便是Java人员也发现它具有足够的启发性,
尽管问题是关于使用场地差异的事实。
首先,插图:
现在用可编译的Scala代码进行更详细的描述。
对比差异的解释(图1的左侧部分)
考虑以下能源层次结构,从非常一般到非常具体:
现在考虑具有单个
让我们实现一些这个特性的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | object Fire extends Consumer[EnergySource] { def consume(a: EnergySource): Unit = a match { case b: Bamboo => println("That's bamboo! Burn, bamboo!") case v: Vegetables => println("Water evaporates, vegetable burns.") case c: EnergySource => println("A generic energy source. It burns.") } } object GeneralistHerbivore extends Consumer[Vegetables] { def consume(a: Vegetables): Unit = a match { case b: Bamboo => println("Fresh bamboo shoots, delicious!") case v: Vegetables => println("Some vegetables, nice.") } } object Panda extends Consumer[Bamboo] { def consume(b: Bamboo): Unit = println("Bamboo! I eat nothing else!") } |
现在,为什么
一些不同的能源,然后将它们喂给各种消费者:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | val oilBarrel = new EnergySource val mixedVegetables = new Vegetables val bamboo = new Bamboo Fire.consume(bamboo) // ok Fire.consume(mixedVegetables) // ok Fire.consume(oilBarrel) // ok GeneralistHerbivore.consume(bamboo) // ok GeneralistHerbivore.consume(mixedVegetables) // ok // GeneralistHerbivore.consume(oilBarrel) // No! Won't compile Panda.consume(bamboo) // ok // Panda.consume(mixedVegetables) // No! Might contain sth Panda is allergic to // Panda.consume(oilBarrel) // No! Pandas obviously cannot eat crude oil |
结果是:
反过来
因此,只要我们只关心消耗能源的能力,
在需要
和
在需要
因此,
类型参数完全相反:
1 2 3 4 5 6 7 8 9 | type >:>[B, A] = A <:< B implicitly: EnergySource >:> Vegetables implicitly: EnergySource >:> Bamboo implicitly: Vegetables >:> Bamboo implicitly: Consumer[EnergySource] <:< Consumer[Vegetables] implicitly: Consumer[EnergySource] <:< Consumer[Bamboo] implicitly: Consumer[Vegetables] <:< Consumer[Bamboo] |
协方差解释(图1的右侧部分)
定义产品层次结构:
1 2 3 |
定义可以生成
定义不同专业水平的各种"来源"/"生产者":
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | object BrowseYoutube extends Producer[Entertainment] { def get: Entertainment = List( new Entertainment { override def toString ="Lolcats" }, new Entertainment { override def toString ="Juggling Clowns" }, new Music { override def toString ="Rick Astley" } )((System.currentTimeMillis % 3).toInt) } object RandomMusician extends Producer[Music] { def get: Music = List( new Music { override def toString ="...plays Mozart's Piano Sonata no. 11" }, new Music { override def toString ="...plays BBF3 piano cover" } )((System.currentTimeMillis % 2).toInt) } object MetalBandMember extends Producer[Metal] { def get = new Metal { override def toString ="I" } } |
基本上任何类型的娱乐:猫视频,杂耍小丑,或(意外)
一些音乐。
这个
产生音乐(即使对任何特定类型没有限制)。
最后,
只有非常具体的
让我们尝试从这三个对象中获取各种
1 2 3 4 5 6 7 8 9 10 11 | val entertainment1: Entertainment = BrowseYoutube.get // ok val entertainment2: Entertainment = RandomMusician.get // ok val entertainment3: Entertainment = MetalBandMember.get // ok // val music1: Music = BrowseYoutube.get // No: could be cat videos! val music2: Music = RandomMusician.get // ok val music3: Music = MetalBandMember.get // ok // val metal1: Entertainment = BrowseYoutube.get // No, probably not even music // val metal2: Entertainment = RandomMusician.get // No, could be Mozart, could be Rick Astley val metal3: Entertainment = MetalBandMember.get // ok, because we get it from the specialist |
我们看到所有三个
我们发现只有
最后,我们看到只保证极其专业的
产生
对于
一般来说,是生产者
可以为不太专业的生产者提供更具体的产品:
1 2 3 4 5 6 7 | implicitly: Metal <:< Music implicitly: Metal <:< Entertainment implicitly: Music <:< Entertainment implicitly: Producer[Metal] <:< Producer[Music] implicitly: Producer[Metal] <:< Producer[Entertainment] implicitly: Producer[Music] <:< Producer[Entertainment] |
产品之间的子类型关系与之间的子类型关系相同
产品的生产者。这就是协方差的意思。
相关链接
关于Java 8中
Java 8
经典"在我自己的
好。
类
例如,采用一个参数的函数具有以下定义:
1 |
问题是,对于函数
但为什么?为什么不相反呢?这是一个有希望更直观地解释它的例子 - 想象两个具体的函数,一个是另一个的子类型:
函数
1 |
我希望我能够澄清一下,随时提出进一步的问题。