zoukankan      html  css  js  c++  java
  • scala 学习: 逆变和协变

    scala 逆变和协变的概念网上有很多解释, 总结一句话就是

    参数是逆变的或者不变的,返回值是协变的或者不变的。

    但是为什么是这样的?

    协变:

    当s 是A的子类, 那么func(s) 是func(A)的子类。 也就是被参数化类型的泛化方向与参数类型的方向是一致的,所以称为协变。 

    个人理解的func(s) 是func(A)的子类的意思是: func(s)的返回值是func(A)的返回值的子类。

    逆变:

    同协变定义,但是是反过来,即当S是A的子类时,func(S)是func(A)的父类。

     如下图所示:

     为什么函数的参数是逆变 而函数的返回值是协变呢?

    根据上面的解释: 入参是用来消费的, 如:animal > bird > dodo   

    假设有一个函数用来输出鸟类的叫声,func[-T],  这时 函数可以接受的参数为bird 和animal, 是合理的。

    如果定义为func[+T], 函数接受的参数为 bird 和dodo, 对于参数为dodo类型来说,传另一个鸟如燕子, 则会出错。因此不符合要求。

    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>

      

    同理如返回值。 

  • 相关阅读:
    html5 返回当前地理位置的坐标点(经纬度)
    C#趣味程序---百鸡百钱
    Android开发:怎样隐藏自己的app应用
    Android Studio一些简单设置
    集群通信组件tribes之集群的消息接收通道
    Java基础实例
    如何用webbrowser获取ajax动态生成的网页的源码?
    phantomjs 下拉滚动条获取网页的全部源码
    Nodejs+定时截图+发送邮件
    关注网页的更新状况,了解最新的handsup 消息.
  • 原文地址:https://www.cnblogs.com/missmzt/p/5999210.html
Copyright © 2011-2022 走看看