美文网首页
Flow中对逆变和协变的处理

Flow中对逆变和协变的处理

作者: 张培_ | 来源:发表于2018-09-25 20:24 被阅读20次

    协变逆变不变的解释

    Employee extend Person
    
    f(Employee)  ?  f(Person)
    

    协变:
    f(Employee) extend f(Person)

    逆变:
    f(Person) extend f(Employee)

    不变:
    f(Employee) 与 f(Person) 无关

    flow中如何处理这样的关系呢?

    协变

    背景

    //Employee extend Person
    
    const employeeObj: {who: Employee} = {who: new Employee('zp','baidu')};
    
    const personObj: {who: Person} = {who: new Employee('haha','ali')};
    

    假设协变成立:

    const personObj: {who: Person} = employeeObj
    //事实是报错了。  ---> 说明{who}是不变的
    

    此时


    image.png
    const personObj.who = new Person('gx');
    //导致内存中的变量被修改
    
    image.png

    此时
    employeeObj: {who: Employee} 也指向这片内存
    由于在面向对象语言中,可以将子实例赋值给父引用(自动转换),但是不能将父实例赋值给子引用
    因此这样做会直接报错。

    flow解决方案:

    const personObj: {+who: Person} = employeeObj;
    
    • flow中的+代表这个属性是一个只读不写的属性readonly属性

    只要保证personObj没有对who属性的写权限,personObj就没有办法给who赋值一个person实例,因此不会出错

    逆变

    背景

    //Employee extend Person
    
    const employeeObj: {who: Employee} = {who: new Employee('zp','baidu')};
    
    const personObj: {who: Person} = {who: new Employee('haha','ali')};
    

    假设逆变成立(父实例可以赋值给子引用):

    const employeeObj: {who: Employee} = personObj
    //事实是报错了。  ---> 说明{who}是不变的
    

    此时


    image.png
    const employee1: Employee =  employeeObj.who
    //employeeObj.who 返回的类型是`Person实例` 根本没有办法将父实例赋值给子引用 直接报错
    

    由于在面向对象语言中,可以将子实例赋值给父引用(自动转换),但是不能将父实例赋值给子引用
    因此这样做会直接报错。

    flow解决方案:

    const employeeObj: {-who:Employee} = personObj;
    
    • flow中的-代表这个属性是一个只写不读的属性writeonly属性

    只要保证employeeObj没有对who属性的读权限,employeeObj就没有办法提取who值赋值一个Employee,因此不会出错

    Demo

    • 协变demo
    // @flow
    import Person from './entity/Person';
    import Employee from './entity/Employee';
    
    const employeeObj: {who: Employee} = {who: new Employee('zp','baidu')};
    // Case1: 上面的定义可以正常work;
    const personObj: {who: Person} = {who: new Employee('haha','ali')};
    // Case2: 给类型是Person的who属性赋值Employee对象,可以正常work
    const personObjError: {who: Person} = employeeObj;
    // Case3: 当我们想要按照上面处理,发现不work
    /*
    Employee 继承 Person
    ==> 使用协变函数: {who} 希望结果:
    {who: Employee} 继承 {who: Person}
    --> 结果不work,因为根本就是不变的
     */
    
    
    const personObjRight: {+who: Person} = employeeObj;
    /*
    + 是只读操作符
    personObjRight  -->              内存
                           |{who: new Employee('zp','baidu')}|
    employeeObj     -->
    ----------------------------------------------------
    假设此时
    personObjRight.who = new Person('gx');
    
    personObjRight  -->              内存
                           |{who: new Person('gx')}|
    employeeObj     -->
    // 那么
    必然导致 employeeObj 直接的who属性被赋值了父实例
     */
    
    
    • 逆变demo
    // @flow
    import Person from './entity/Person';
    import Employee from './entity/Employee';
    
    const employeeObj: {who: Employee} = {who: new Employee('zp','baidu')};
    // Case1: 上面的定义可以正常work;
    const personObj: {who: Person} = {who: new Person('guoxin')};
    // Case2: 给类型是Person的who属性赋值Employee对象,可以正常work
    const employeeObjError: {who: Employee} = personObj;
    // Case3: 当我们想要按照上面处理,发现不work
    /*
    Employee 继承 Person
    ==> 使用逆变函数: {who} 希望结果:
    {who: Person} 继承 {who: Employee}
    --> 结果不work,因为根本就是不变的
     */
    
    
    const employeeObjRight: {-who: Employee} = personObj;
    /*
    - 是只写操作符
    employeeObjRight  -->              内存
                           |{who: new Person('guoxin')}|
    personObj         -->
    ----------------------------------------------------
    假设此时
    Employee employee = employeeObjRight.who // 读出who的value
    绝对不可以将父实例赋值给子类
    
    personObjRight  -->              内存
                           |{who: new Employee('gx')}|
    employeeObj     -->
     */
    

    相关文章

      网友评论

          本文标题:Flow中对逆变和协变的处理

          本文链接:https://www.haomeiwen.com/subject/znxroftx.html