安卓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高階函數的定義方法和簡單使用,還提了一下內聯函數,但沒有細説,後面還會在本文進行補充,將一些情況補上。