安卓Kotlin開發學習——接著看高階函式

語言: CN / TW / HK

theme: devui-blue

開啟掘金成長之旅!這是我參與「掘金日新計劃 · 2 月更文挑戰」的第 16 天,點選檢視活動詳情

引言

前面我們看過了安卓Kotlin的高階函式的定義(安卓開發之Kotlin學習——初遇高階函式 - 掘金 (juejin.cn)),但是還沒在實際開發環境使用,本篇我們一起來看看高階函式使用的例項與使用方法,繼續學習Kotlin高階函式。

正文

首先讓我們先寫一個簡單的高階函式: Kotlin fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int { return operation(num1, num2) } 我們在高階函式num1AndNum2裡傳入三個引數,分別兩個整型和最後一個函式型別引數operation,operation是一個可以傳入兩個Int引數並返回Int型別值的函式型別引數,然後num1AndNum2返回值為Int型別,在結構體中將該返回值設定為傳入num1和num2的operation函式返回值。

如果要呼叫上述高階函式,我們必須為其傳入一個(Int, Int) -> Int型別的函式,所以我們可以在定義與之相匹配的函式: ```Kotlin fun plus(num1: Int, num2: Int): Int { return num1 + num2 }

fun minus(num1: Int, num2: Int): Int { return num1 - num2 } 於是我們定義了上面兩個函式,分別是兩數相加和兩數相減,接下來我們看看呼叫高階函式的方式: val num1 = 200 val num2 = 100 val addNum = num1AndNum2(num1, num2, ::plus) val minusNum = num1AndNum2(num1, num2, ::minus) ``` 我們看到上面的呼叫方式與我們平常的函式呼叫有些許不同,我們在傳遞第三個引數(函式型別)是在需要呼叫的函式的函式名前加了符號“::”,這是一種函式引用方式的寫法,表示將我們的對應函式作為引數傳入高階函式中,而我們定義的高階函式就會以傳入的函式型別引數來決定具體的運算邏輯,這麼一看,其實我們上面的例子就是廢話文學,實際上還是呼叫了plus()和minus()函式去運算,不過包了一層高階函式罷了,當然,這裡只是wield學習來舉例高階函式的使用,這個簡單的例子也更加方便學習。

上面的寫法顯得很囉嗦,每次去定義新的函式來為高階函式傳遞,實在太麻煩,所以下面我們將使用之前說過的Lambda表示式(安卓語言基礎之Kotlin高階函式——Lambda表示式(一) - 掘金 (juejin.cn)安卓語言基礎之Kotlin高階函式——Lambda表示式(二) - 掘金 (juejin.cn))去簡化上面的寫法,對,我們的高階函式也支援Lambda表示式,而且這似乎是最常見和最普遍的高階函式呼叫方式: Kotlin val num1 = 200 val num2 = 100 val addNum = num1AndNum2(num1, num2) { n1, n2 -> n1 + n2 } val minusNum = num1AndNum2(num1, num2) { n1, n2 -> n1 - n2 } Lambda表示式的寫法就可以省去我們重新定義函式的步驟。

在之前安卓語言基礎之Kotlin高階函式——Lambda表示式(二) - 掘金 (juejin.cn)的實際應用中,我們使用了apply函式,它可以用於給Lambda表示式提供一個指定的上下文,當連續呼叫同一個物件的多個方法時它就會讓程式碼更為精簡,如下:

image.png 就拿上面的例子來說,我們可以先給StringBuilder類定義一個擴充套件函式build,讓這個擴充套件函式來接受一個函式型別引數,返回值型別也同樣是StringBuilder,這樣我們就能用高階函式去實現於apply函式類似的功能: Kotlin fun StringBuilder.build(block: StringBuilder.() -> Unit) : StringBuilder { block() return this } 我們可以看到上面的程式碼中與我們之前宣告函式型別的方式不一樣,它在函式型別前加了一個StringBuilder. 的語法結構,其實這才是定義高階函式完整的語法規則,要在函式型別的前面加上ClassName,這就能明確表示這個函式型別是定義於哪個類中。

而我們此處加類名的意義在於,我們如果明確了StringBuilder類中,那我們在呼叫高階函式build時傳入的Lambda表示式將能自動擁有StringBuilder的上下文,同時這也是apply函式的實現方式,但我們寫的也只能作用於StringBuilder類,而apply函式是可以作用於所以類上面,如果想實現這個效果,我們還得藉助Kotlin的泛型,所以後面我們的文章中會分享一些泛型的知識。

我們接著看呼叫的例項: ``` val listA = listOf("Apple", "Pear", "Banana")

val resultA = StringBuilder().build { append("start add. \n") for (fruit in listA) { append(fruit).append("\n") } append("All fruits.") } println(resultA.toString()) ``` 我們可以看到和apply函式的呼叫並無區別。

行內函數

我們在前面呼叫Kotlin的高階函式時使用Lambda表示式,其實從Java層來說,Kotlin還是使用了Java的匿名函式,每調一次Lambda表示式,就會建立一個新的匿名類例項,而這也將會造成額外的記憶體和效能開銷。

為了消除這一影響,Kotlin就提供了行內函數的方法,它能將使用的Lambda表示式帶來的執行時開銷消除,實現方法很簡單,我們用到關鍵字inline,並將其加在我們定義的高階函式前面即可: inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int { return operation(num1, num2) }

總結

這裡我們主要介紹完了Kotlin高階函式的定義方法和簡單使用,還提了一下行內函數,但沒有細說,後面還會在本文進行補充,將一些情況補上。