翻譯說明:
原標題: Parameters and Arguments: An Easy Way to Remember the Difference
原文地址: typealias.com/guides/para…
原文作者: Dave Leeds
簡述(俗稱扯皮):
最近在深入研究Kotlin中的泛型語法,發現它和Java中的泛型有著很大不同,在語法上Kotlin的泛型也會比Java中的使用起來更安全。但是發現Kotlin泛型一時間冒出了很多的名詞術語,什麼協變、逆變、不變、星投影啊;什麼實化引數、型別形參、型別實參啊,什麼類、型別、子類、子型別、超型別弄得是一臉懵逼. 不過還好基本都弄懂了,於是乎想準備一系列關於Kotlin中泛型的部落格來記錄我的坎坷,希望能有所幫助。
以下是我之前的一些關於Kotlin的文章,如感興趣歡迎檢視:
翻譯系列:
- [譯]Kotlin中是應該定義函式還是定義屬性?
- [譯]如何在你的Kotlin程式碼中移除所有的!!(非空斷言)
- [譯]掌握Kotlin中的標準庫函式: run、with、let、also和apply
- [譯]有關Kotlin型別別名(typealias)你需要知道的一切
- [譯]Kotlin中是應該使用序列(Sequences)還是集合(Lists)?
- [譯]Kotlin中的龜(List)兔(Sequence)賽跑
- [譯]Effective Kotlin系列之考慮使用靜態工廠方法替代構造器(一)
- [譯]Effective Kotlin系列之遇到多個構造器引數要考慮使用構建器(二)
原創系列:
- 有關Kotlin屬性代理你需要知道的一切
- 淺談Kotlin中的Sequences原始碼解析
- 淺談Kotlin中集合和函式式API完全解析-上篇
- 淺談Kotlin語法篇之lambda編譯成位元組碼過程完全解析
- 淺談Kotlin語法篇之Lambda表示式完全解析
- 淺談Kotlin語法篇之擴充套件函式
- 淺談Kotlin語法篇之頂層函式、中綴呼叫、解構宣告
- 淺談Kotlin語法篇之如何讓函式更好地呼叫
- 淺談Kotlin語法篇之變數和常量
- 淺談Kotlin語法篇之基礎語法
實戰系列:
- 用Kotlin擼一個圖片壓縮外掛ImageSlimming-導學篇(一)
- 用Kotlin擼一個圖片壓縮外掛-外掛基礎篇(二)
- 用Kotlin擼一個圖片壓縮外掛-實戰篇(三)
- 淺談Kotlin實戰篇之自定義View圖片圓角簡單應用
今天是一篇簡單的部落格翻譯作為Kotlin泛型語法系列開場白:
進入正題(開始翻譯啦...)
你是否曾經很難記住形參和實參的區別,今天這篇文章就是為了量身打造的。理清它們之間的區別可以幫助你更好地深入理解函式,此外甚至可以更多幫助你理解泛型。
形式引數與實際引數
- 定義在裡面就是形式引數(形參)
- 定義在外面就是實際引數(實參)
回憶兩者之間的差異的最簡單的簡單的方法就是將arugment單詞與outside單詞關聯起來,記住這句話
“Take your argument outside!”
這裡有我畫的一張卡通圖幫你去記住它:
有關更多說明,讓我們看一下函式和泛型類的示例。
函式中的形參與實參
這是一個對整數進行平方的簡單函式。將傳遞哪些資料?只是我們想要平方的數字。
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,歡迎加入我們~~~