scala的函數爲什麼參數都是逆變的而返回值都是協變的

在scala中,函數特質的定義都是類似下面的:

trait FunctionN[-T1, -T2,-T3...-TN, +R] extends AnyRef

也就是說參數都輸逆變的,返回值都是協變的。在scala中,函數是一等公民,他可以像數組(數組也是支持逆變和協變的)被賦值和傳參。所以函數必須要被支持賦值操作。如果一個函數要想賦值給另一個函數的指針(無論是直接賦值還是當做函數傳參),函數的參數必須是指針(函數的指針)參數相同的類型或者父類型,返回值必須是指針(函數的指針)返回值的相同類型或者子類型。比如說有一個指針f1:

f1 : (Son1) => Father 2 // Son1 extend Father1,Son2 extend Father2

然後有一個函數f2:

f2 : (father1) => son2

現在把f2賦值給f1是沒有問題的。

f1 = f2

爲什麼可以這樣?
我們先約定一下稱謂。我們把(Son1) => Father 2稱作f1的定義類型。當f1被f2賦值後,f1的類型是(father1) => son2 我們稱之爲f1的運行類型。使用者使用被賦值後的f1時只知道f1的定義類型,而不知道f1的運行類型(只有jvm知道)那我們只會傳給被賦值後的f1 Son1類型的參數,也只會把被賦值後的f1的返回值當做Father2來用。其中內在的賦值邏輯就是:

  • 對於參數:f1定義的類型(使用者傳給函數的)-> f1運行時的類型
  • 對於返回值:f1運行後的返回值類型 -> f1 定義的返回值類型(使用者希望獲得的類型)

假設我們現在要使用f1指向的函數,我們給傳個Son1類型的參數,但是實際上f1代表的是f2類型的函數,也就相當於我們把Son1傳給(father1) => son2。根據泛型,這當然沒有問題。j現在f2的參數是Son1的子類型,那顯然是不行的。返回值也是這個道理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章