[譯] 一個簡單方式教你記住Kotlin的形參和實參

極客熊貓發表於2018-10-16

翻譯說明:

原標題: Parameters and Arguments: An Easy Way to Remember the Difference

原文地址: typealias.com/guides/para…

原文作者: Dave Leeds

簡述(俗稱扯皮):

最近在深入研究Kotlin中的泛型語法,發現它和Java中的泛型有著很大不同,在語法上Kotlin的泛型也會比Java中的使用起來更安全。但是發現Kotlin泛型一時間冒出了很多的名詞術語,什麼協變、逆變、不變、星投影啊;什麼實化引數、型別形參、型別實參啊,什麼類、型別、子類、子型別、超型別弄得是一臉懵逼. 不過還好基本都弄懂了,於是乎想準備一系列關於Kotlin中泛型的部落格來記錄我的坎坷,希望能有所幫助。

以下是我之前的一些關於Kotlin的文章,如感興趣歡迎檢視:

翻譯系列:

原創系列:

實戰系列:

今天是一篇簡單的部落格翻譯作為Kotlin泛型語法系列開場白:

進入正題(開始翻譯啦...)

你是否曾經很難記住形參和實參的區別,今天這篇文章就是為了量身打造的。理清它們之間的區別可以幫助你更好地深入理解函式,此外甚至可以更多幫助你理解泛型。

形式引數與實際引數

  • 定義在裡面就是形式引數(形參)
  • 定義在外面就是實際引數(實參)

回憶兩者之間的差異的最簡單的簡單的方法就是將arugment單詞與outside單詞關聯起來,記住這句話

“Take your argument outside!

這裡有我畫的一張卡通圖幫你去記住它:

[譯] 一個簡單方式教你記住Kotlin的形參和實參

有關更多說明,讓我們看一下函式和泛型類的示例。

函式中的形參與實參

這是一個對整數進行平方的簡單函式。將傳遞哪些資料?只是我們想要平方的數字。

fun square(number: Int): Int {
    return number * number
}
複製程式碼

在這個函式的定義裡面,我們說number就是一個形式引數

現在已經定義好了我們的函式,當我們呼叫它時,會將一些資料傳遞給這個函式。

val radius = 5
val area = Math.PI * square(radius)
複製程式碼

這裡,在函式定義的外面,我們說radius是square函式的實際引數

泛型中的形參與實參

泛型類是具有一種或多種型別的類。例如,這裡有個非常簡單的Box類,它只包含其他一些物件。

class Box<T>(var item: T)
複製程式碼

這裡,在Box類定義的裡面,我們說T是一個型別形參

使用這個類十分簡單,我們只需要呼叫它的構造器,並傳入一些符合正確型別的資料進去即可。

val box = Box<String>("Hello")
複製程式碼

這裡,在Box類定義的外面,我們使用String型別實參去構造它。

事實上,Kotlin做了一些智慧的型別推導,所以我們甚至不必明確指定它:

val box = Box("Hello")
複製程式碼

在這種情況下,它仍然有一個String型別的型別實參。它只是隱含在我們傳遞給建構函式的“Hello”實際引數的型別中而已。

總結

再次說明下,在函式和泛型類/介面兩種情況下,結論是:

  • 形參 - 在定義裡面
  • 實參 - 在定義外面

讀者有話說

其實這篇文章目的很簡單就是幫助理解一個問題:Kotlin中泛型形參和實參區別。因為這兩個術語將會在後續泛型文章中被多次提到。所以如果不提前弄懂這些名詞概念,後面一些深入的東西理解起來會非常吃力的。我補充幾點:

  • 第一: 為了驗證一下理論,我們一起分析下下面兩個例子:
class StringList: List<String>{
    ...
}
複製程式碼

對於以上例子很好理解,StringList類實現List介面,提供了具體的型別實參: String,可以看到String明顯是在List介面定義的外面,所以它就是型別實參

class ArrayList<T>: List<T>{
    ...
}
複製程式碼

關於這個例子,大家看看怎麼分析呢?? 實際上很簡單就按照這篇文章作者說的那樣抓住問題關鍵點: 型別引數在類或介面定義外面還是裡面,裡面就是形參,外面就是實參

所以,這裡例子很容易分析出這個T是List介面的型別實參,而不一樣的是這個T同時還是ArrayList這個類的型別形參。ArrayList類中定義了自己的型別形參T,並把指定為父類(List介面)型別的實參。在Kotlin的泛型中有這樣規定: 如果一個類繼承泛型類(或者實現了泛型介面),就必須為基礎型別的泛型形參指定一個泛型實參。它可以是具體的型別或者另一個型別形參。所以你會發現ArrayList 中的T和List中的T實際上有所不一樣的,就是型別形參和型別實參的區別。

  • 第二、初學者很容易走進一個誤區,認為類似T,K,V這種沒有具體意義的型別就是型別形參,而像String,Int這種具體有意義的型別就是型別實參。這種理解是錯誤,總之可以按照原文作者那樣理解。
  • 第三,在Kotlin中規定所有的泛型實參需要顯示的宣告,要麼能被編譯器智慧推匯出來。也就是不能像Java中那樣直接一個List(Java中原生態型別)就行,不用指定泛型實參,這種情況在Kotlin中不允許的,編譯器就會報錯。所以不得不誇下Kotlin了,它語法上非常嚴謹和明確,不能含糊,在定義和宣告就必須明確下來。
  • 第四,泛型函式中也有自己的型別形參,在每次函式執行呼叫時型別形參會被替換成型別實參,有點函式中形參和實參。

這是泛型系列文章簡單的開場白,下面將會繼續深入Kotlin泛型相關內容,例如泛型擦除以及實化型別引數,泛型協變,逆變,星投影。歡迎繼續關注~~

[譯] 一個簡單方式教你記住Kotlin的形參和實參

歡迎關注Kotlin開發者聯盟,這裡有最新Kotlin技術文章,每週會不定期翻譯一篇Kotlin國外技術文章。如果你也喜歡Kotlin,歡迎加入我們~~~

相關文章