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;
- 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 -->
*/