為什麼Kotlin中沒有使用Void作為返回型別

語言: CN / TW / HK

theme: cyanosis highlight: androidstudio


為什麼Kotlin中沒有使用Void作為返回型別

持續創作,加速成長!這是我參與「掘金日新計劃 · 6 月更文挑戰」的第26天,點選檢視活動詳情

0_15Pa1eXhWQTTIWNU.png

Kotlin是一種帶有很多語法糖的語言。儘管它是一種面向物件的語言。但是在Kotlin中是函式作為一等公民,而不是物件。這一個特性就決定了它可以使用函式進行傳遞和返回。因此,Kotlin中的高階函式應用就很廣。高階函式至少就需要一個函式作為引數,或者返回一個函式。

在Kotlin中沒有不敢回任何內容的函式。在Java中我們可以使用void來表示函式不返回任何內容,但是在Kotlin中的函式總是要返回一些內容。如果我們沒有在明明函式宣告中明確的指定返回型別,或者沒有在Lambda函式中明確返回任何內容,它就會返回Unit。下面的示例實際時相同的

```kotlin fun funcionNoReturnAnything(){

} fun funcionNoReturnAnything():Unit{

} ```

或者是在lambda函式體中最後一個值會作為返回值返回,如果沒有明確返回,就會預設返回Unit

```kotlin view.setOnclickListener{

} view.setOnclickListener{ Unit
} ```

儘管他們在寫法上會有一些不同,但是Unit同Java中的Void在含義上都是一樣的,如果在Kotlin程式碼中嗲用Java中不會返回任何內容的方法,將返回的是Unit,而不是Void。在Kotlin中Unit是一個單例描述者函式不會返回任何有用的值

我們試著去建立一個Kotlin中的高階函式,看看反編譯背後的Java程式碼是怎麼實現的

kotlin fun run(block:() -> Unit){ block() }

run函式接受一個名為“block”的引數,該引數具有函式型別“() -> Unit”,這意味著塊本身是一個不帶引數並返回 Unit 的函式。反編譯的Java程式碼如下:

java public static final void run(@NotNull Function0 block){ Instrinsics.checkNotNullParameter(block,"block"); block.invoke(); }

在底層,函式run採用一個名為block的引數,就像在原始 Kotlin 程式碼中一樣。但是,引數的型別在這裡稱為“Function0”。由於我們在 Java 中實際上沒有函式型別,因此使用智慧實現來提供與 Java 的完整互操作性。看原始碼就可以理解了

java public interface Function0<out R>:Funciton<R>{ public operator fun invoke():R }

可以看出Fuction0是一個泛型介面,它表示一個不帶引數並返回泛型型別 R 的函式型別。該介面有一個方法“invoke”,在呼叫此函式時會呼叫該方法。Kotlin 的函式型別被實現為這個通用介面的匿名物件,其中函式體被實現為“invoke”方法的主體。對於引數最多為 22 的函式,還有其他類似的介面。

為了保持與預設情況下沒有函式型別並且需要面向物件的方法(建立已定義介面的匿名類的物件)來建立值儲存函式的 Java 的互操作性,需要一個類來使編譯器能夠在下面使用泛型,同時保持“不返回(有用的)值”的概念

此外,每當我們建立 lambda、傳遞 noinline 函式作為引數或建立對函式型別的引用時,都會建立相應介面的匿名類的物件。每當我們想要傳遞函式時,Kotlin 都會簡單地將我們從 Java 的樣板檔案中拯救出來。當我們通過在其引用名稱後新增括號來呼叫函式時,將呼叫前面提到的介面之一的運算子“invoke”方法。運算子函式可以通過相應的運算子呼叫,invoke 函式對應於“invoke operator” =>()。您可以在下面看到兩種呼叫函式型別的方法:

kotlin fun run(block:() -> Unit){ block() //或者是使用這種方式都是允許的 block.invoke() }