Flow中对逆变和协变的处理

2018-09-25  本文已影响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;

只要保证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;

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

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属性被赋值了父实例
 */

// @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     -->
 */
上一篇下一篇

猜你喜欢

热点阅读