• 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>

      

    同理如返回值。 

  • 相关阅读:
    Android Training精要(二)開啟ActionBar的Overlay模式
    Android Training精要(一)ActionBar上级菜单导航图标
    SimpleDateFormat的线程安全问题
    svn删除目录后提交显示Item 'XXXX' is out of date解决方法
    使用 python 开发 Web Service
    Bootstrap 中文文档教程
    起步 简介整个项目、组件、和如何使用一个简单的模版入门
    mysql笔记——索引
    20个数据库设计的最佳实践
    ASP.NET MVC Bootstrap极速开发框架
  • 原文地址:https://www.cnblogs.com/missmzt/p/5999210.html
Copyright © 2020-2023  润新知