scala – 如何检查函数中元素的协变和逆变位置?
这是我阅读的有关
scala中的逆变和协方差的文章之一的代码片段.但是,我无法理解scala编译器抛出的错误消息“错误:协变类型A出现在值pet2的类型A中的逆变位置
class Pets[+A](val pet:A) { def add(pet2: A): String = "done" } 我对这段代码片段的理解是,Pets是协变的并且接受A的子类型的对象.但是,函数add仅接受A类型的参数.Being covariant意味着Pets可以获取A类及其子类型的参数.那怎么会抛出错误呢.从哪里出现逆变问题. 对上述错误消息的任何解释都将非常有用.谢谢 解决方法
TL; DR:
>您的Pets类可以通过返回成员变量pet来生成类型A的值,因此Pet [VeryGeneral]不能是Pet [VerySpecial]的子类型,因为当它生成VeryGeneral时,它不能保证它也是一个实例非常特别.因此,它不能逆变. 唯一剩下的可能性是:宠物必须在A中保持不变. 举例说明:协方差与逆差: 我将利用这个机会提出一个改进的,显着的更多 首先,插图: 现在用可编译的Scala代码进行更详细的描述. 对比差异的解释(图1的左侧部分) 考虑以下能源层次结构,从非常一般到非常具体: class EnergySource class Vegetables extends EnergySource class Bamboo extends Vegetables 现在考虑具有单一消费(a:A)方法的特征消费者[-A]: trait Consumer[-A] { def consume(a: A): Unit } 让我们实现一些这个特性的例子: 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!") } 现在,为什么消费者必须在A中逆变?让我们尝试实例化 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 结果是:火可以消耗GeneralistHerbivore可以消耗的所有东西, 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的右侧部分) 定义产品层次结构: class Entertainment class Music extends Entertainment class Metal extends Music // yes,it does,seriously^^ 定义可以生成A类值的特征: trait Producer[+A] { def get: A } 定义不同专业水平的各种“来源”/“生产者”: 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" } } BrowseYoutube是最通用的娱乐来源:它可以给你 RandomMusician已经有点专业了,至少我们知道这个对象 最后,MetalBandMember非常专业:get方法保证返回 让我们尝试从这三个对象中获取各种娱乐: 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 我们看到所有三个制片人[娱乐],制片人[音乐]和制片人[金属]都可以制作某种娱乐. implicitly: Metal <:< Music implicitly: Metal <:< Entertainment implicitly: Music <:< Entertainment implicitly: Producer[Metal] <:< Producer[Music] implicitly: Producer[Metal] <:< Producer[Entertainment] implicitly: Producer[Music] <:< Producer[Entertainment] 产品之间的子类型关系与之间的子类型关系相同 相关链接 >类似的讨论?延伸A和? Java 8中的超级B: (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 【WebService】3.使用CXF开发WebService客户端
- scala – 如何更改功能测试的Guice绑定?
- bash – 将conda环境信息添加到终端提示符
- Angular 2问题获取选择选项值
- 如何在fread中处理Coverity错误TAINTED_SCALAR
- angular – 自定义错误处理程序抛出错误:无法读取未定义的
- axis2的方法调用以及302 Error: Moved Temporarily的解决方
- angular – 我怎样才能“修补”一个Observable for Zone.js
- 根据Angular 2中的条件在组件中加载不同的模板
- 几种流行Webservice框架性能对比(转载、拼接)