昨天收尾了類別的介紹,剛好借助了類別物件的概念加上前面函式的介紹,今天我們來推敲一下擴充函式 (extension function
) 到底是怎麼做到對所有型別或是資料結構型別 (例如: List<Int>
) 進行函式擴充。
首先我們根據 Kotlin 官方文件可以知道擴充函式都是被靜態處理的,這裡忽略靜態這個詞,其實就是在程式碼寫好後,擴充函式就會依照定義去執行賦予的任務,模仿一下官方範例:
open class Person
class Employee: Person()
// defining the getType() extension function on Person
fun Person.getType() = "Generic person"
// defining the getType() extension function on Employee
fun Employee.getType() = "Employee"
fun getPersonType(person: Person) : String {
return person.getType()
}
fun getEmployeeType(person: Person) : String {
return person.getType()
}
fun main() {
print(getPersonType(Employee())) // Generic person
print(getEmployeeType(Employee()))// Employee
}
這個範例顯示如果我們在擴充函式定義前的型別會影響擴充函式的行為。
好,我們知道用法跟限制後,但還是沒有解決擴充函式在編譯階段是怎樣被 Kotlin 編譯器處理的。Kotlin 官方文件並沒有直接提及,所以我們問一下估狗跟 GPT 老師靜態處理下的擴充函式,加上一點想像力後,我猜測因為編譯器會幫我們把程式碼編譯成一個新類別與半生物件然後再讓有使用到的函式去呼叫他如下:
原始程式碼:
fun String.reverse(): String = this.reversed()
val test = "test string"
print(test.reverse()) // gnirts tset
Kotlin 編譯器加工:
class StringExtension {
companion object {
@JvmStatic
fun reverse(str: String): String {
return str.reversed()
}
}
}
fun main(){
val test = "test string"
print(StringExtension.reverse(test)) // gnirts tset
}
但這時候讀可能會想到說,之前好像也有說過如果我直接用物件放似乎也是可以做到靜態生成:
object StringExtension {
@JvmStatic
fun reverse(str: String): String {
return str.reversed()
}
}
fun main(){
val test = "test string"
print(StringExtension.reverse(test)) // gnirts tset
}
對,確實這樣也是可以達成,所以這也是我所推測的一種可能性。
今天的內容比較像是突發奇想的內容,其實從開始使用擴充函式後,筆者我就一直很困惑這新鮮玩具是怎麼做到的,所以才會有今天這篇,老實說關於實作內容我也是很難找到相關資源,如果各位大大有不同見解或是詳解的,也歡迎留言區大力鞭策XD
因為 Kotlin 都會 compiler 成 java bytecode, 所以就直接反組譯就好,也不用猜啦