zoukankan      html  css  js  c++  java
  • 协变和逆变

    协变和逆变

    约定:

    • A ≦ B 意味着 A 是 B 的子类型
    • A → B 指的是以 A 为参数类型,以 B 为返回值类型的函数类型
    • x : A 意味着 x 的类型为 A

    协变和逆变的概念可以借助实际的变量类型来理解:

    • 协变和普通变量:

    在 C# 中,List 类实现 IEnumerable 接口,因此 List 实现 IEnumerable

      IEnumerable<Derived> d = new List<Derived>();
      IEnumerable<Base> b = d;
    

    简单来说,协变就和面向对象概念中的多态一样,指可以使用父类型引用指向子类型实例的情况。

    • 逆变和函数变量:

    假如我有这样一个类型链:C ≦ B ≦ A,此时有一个函数是这样的:f(B → B),这个函数接收一个 B → B 函数作为参数, 那么这种情况下,怎样的函数可以作为 f 的参数呢?

    首先,对于 C → * 来说都是不行的,因为 f 调用函数时参数类型可能是 B 或 B 的其他子类型,而 C → * 只支持 C 类型的入参。

    然后,对于 * → A 来说也是不行的,因为 f 要求的返回值是 B 或 B 的其他子类型,但是 * → A 可能会返回 B 的父类型 A。

    最后,对于 A → C 来说却是可行的,因为 f 的参数只会是 B 或 B 的其他子类型,而 A → C 的入参类型是 A,满足。 同时,函数 A → C 的返回值是 C,是 B 的子类型,返回值类型也满足。

    这时,神奇的情况便发生了,当函数类型是 B → B 时,我们可以使用 <? super B> → <? extend B> 进行赋值:

      Action<Base> b = (target) => { Console.WriteLine(target.GetType().Name); };
      Action<Derived> d = b;
    

    这就是逆变。

    参考:

  • 相关阅读:
    linux Segmentation faults 段错误详解
    linux cut
    linux sed
    linux tr
    linux ar
    objdump--反汇编查看
    linux中dd命令
    readelf
    登录后,前端做了哪些工作,如何得知已登录?
    正向代理和反向代理?
  • 原文地址:https://www.cnblogs.com/rgbit/p/14255430.html
Copyright © 2011-2022 走看看