Flow中对逆变和协变的处理

协变逆变不变的解释

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     -->
 */
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容