協(xié)變逆變不變的解釋
Employee extend Person
f(Employee) ? f(Person)
協(xié)變:
f(Employee) extend f(Person)
逆變:
f(Person) extend f(Employee)
不變:
f(Employee) 與 f(Person) 無關(guān)
flow中如何處理這樣的關(guān)系呢?
協(xié)變
背景
//Employee extend Person
const employeeObj: {who: Employee} = {who: new Employee('zp','baidu')};
const personObj: {who: Person} = {who: new Employee('haha','ali')};
假設協(xié)變成立:
const personObj: {who: Person} = employeeObj
//事實是報錯了。 ---> 說明{who}是不變的
此時

image.png
const personObj.who = new Person('gx');
//導致內(nèi)存中的變量被修改

image.png
此時
employeeObj: {who: Employee} 也指向這片內(nèi)存
由于在面向?qū)ο笳Z言中,可以將子實例賦值給父引用(自動轉(zhuǎn)換),但是不能將父實例賦值給子引用
因此這樣做會直接報錯。
flow解決方案:
const personObj: {+who: Person} = employeeObj;
- flow中的
+代表這個屬性是一個只讀不寫的屬性readonly屬性
只要保證personObj沒有對who屬性的寫權(quán)限,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實例` 根本沒有辦法將父實例賦值給子引用 直接報錯
由于在面向?qū)ο笳Z言中,可以將子實例賦值給父引用(自動轉(zhuǎn)換),但是不能將父實例賦值給子引用
因此這樣做會直接報錯。
flow解決方案:
const employeeObj: {-who:Employee} = personObj;
- flow中的
-代表這個屬性是一個只寫不讀的屬性writeonly屬性
只要保證employeeObj沒有對who屬性的讀權(quán)限,employeeObj就沒有辦法提取who值賦值一個Employee,因此不會出錯
Demo
- 協(xié)變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: 當我們想要按照上面處理,發(fā)現(xiàn)不work
/*
Employee 繼承 Person
==> 使用協(xié)變函數(shù): {who} 希望結(jié)果:
{who: Employee} 繼承 {who: Person}
--> 結(jié)果不work,因為根本就是不變的
*/
const personObjRight: {+who: Person} = employeeObj;
/*
+ 是只讀操作符
personObjRight --> 內(nèi)存
|{who: new Employee('zp','baidu')}|
employeeObj -->
----------------------------------------------------
假設此時
personObjRight.who = new Person('gx');
personObjRight --> 內(nèi)存
|{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: 當我們想要按照上面處理,發(fā)現(xiàn)不work
/*
Employee 繼承 Person
==> 使用逆變函數(shù): {who} 希望結(jié)果:
{who: Person} 繼承 {who: Employee}
--> 結(jié)果不work,因為根本就是不變的
*/
const employeeObjRight: {-who: Employee} = personObj;
/*
- 是只寫操作符
employeeObjRight --> 內(nèi)存
|{who: new Person('guoxin')}|
personObj -->
----------------------------------------------------
假設此時
Employee employee = employeeObjRight.who // 讀出who的value
絕對不可以將父實例賦值給子類
personObjRight --> 內(nèi)存
|{who: new Employee('gx')}|
employeeObj -->
*/