幫助理解Kotlin函數(shù)的3個(gè)概念

kotlin&android

人生苦短,我選Kotlin
——筆者

Kotlin相比Java很年輕,也更有潛力,其對(duì)函數(shù)式編程的支持也讓其代碼更加簡(jiǎn)潔,但在理解函數(shù)式編程的過程中,總會(huì)有些障礙,比如筆者在看到apply和with這兩個(gè)方法的時(shí)候,就很奇怪,看了源碼就更加糊涂了,本文以剖析apply和with這兩個(gè)方法為線索,介紹下kotlin中函數(shù)式編程相關(guān)的幾個(gè)概念。

函數(shù)類型(function type)

在函數(shù)式語言中,函數(shù)作為一種類型可以在函數(shù)間傳遞,那么如何區(qū)別不同的函數(shù)的類型呢?
將函數(shù)的入?yún)⒑头祷刂?,作為一種函數(shù)類型,比如:
(Int) -> Int 是一個(gè)函數(shù)類型,它的傳入?yún)?shù)為Int,返回類型為Int,滿足這個(gè)條件的函數(shù)為同一種類型的函數(shù)。

fun double(x: Int): Int {
    return 2 * x
}

比如double這個(gè)函數(shù)的類型為(Int) -> Int,它的入?yún)⑹荌nt,返回值為Int.

由于函數(shù)為一種類型,我們可以像定義Int值一樣定義一個(gè)函數(shù)類型的變量:

val double: (Int) -> Int = fun(value: Int): Int {
    return 2 * value
}

double的類型為函數(shù),函數(shù)類型為(Int) -> Int
函數(shù)作為變量可以傳遞:

val doubleCopy = double
doubleCopy(1)

此時(shí)doubleCopy的類型和double的類型相同

高階函數(shù) (high order function)

如果一個(gè)函數(shù)將一個(gè)函數(shù)作為參數(shù),或者返回一個(gè)函數(shù),那么這種函數(shù)叫做high order function(高階函數(shù))

前面提到函數(shù)可以作為變量進(jìn)行傳遞,將函數(shù)作為參數(shù)傳遞到另一個(gè)函數(shù)中,也是允許的,比如下面的例子:

// lock為高階函數(shù),接受2個(gè)參數(shù),類型分別為:Lock,() -> T
// 前者為常見的Lock類型,后者為一個(gè)函數(shù)類型,這個(gè)類型的函數(shù)入?yún)榭眨祷刂禐門
fun <T> lock(lock: Lock, body: () -> T): T {
    lock.lock()
    try {
        return body()
    }
    finally {
        lock.unlock()
    }
}
// 調(diào)用方法
lock (lock,{sharedResource.operation()})
// 在kotlin中,如果一個(gè)函數(shù)的最后一個(gè)參數(shù)為函數(shù),則可以將這個(gè)函數(shù)的函數(shù)體放到括號(hào)外面,就是常見的下面這種寫法
lock (lock) {
    sharedResource.operation()
}

function-with-receiver type

kotlin中存在一個(gè)比較特殊的函數(shù)類型定義,它指定了函數(shù)的receiver(看起來和擴(kuò)展方法比較像)

理解這個(gè)很關(guān)鍵,kotlin中很多基本的函數(shù)都是基于這種函數(shù)類型來實(shí)現(xiàn)的。

比如下面的代碼段中,聲明了intToLong這個(gè)函數(shù)的receiver類型為Int,只有Int類型的對(duì)象(A)可以調(diào)用intToLong這個(gè)方法,并且在intToLong函數(shù)體內(nèi),可以通過this來調(diào)用A中的函數(shù)

val intToLong: Int.() -> Long = { toLong() }

上面的代碼段中,實(shí)際上調(diào)用的是Int類型本身定義的toLong方法:

//this可以省略掉
val intToLong: Int.() -> Long = { this.toLong() }
//可以編譯通過,調(diào)用時(shí),上面一句中的this即為3
val Long a = 3.intToLong()
//不可以編譯通過,intToLong聲明了receiver,只能被Int類型調(diào)用
val Long b = "3".intToLong()

分析下appy和with方法

這兩個(gè)方法是kotlin中常用的方法,可以簡(jiǎn)化代碼,讓邏輯更加清晰整潔,但直接理解起來會(huì)有點(diǎn)繞,如果你看懂了前面講到的幾個(gè)概念之后,appy和with方法理解起來就相對(duì)容易很多

apply

apply是kotlin中常用的方法,它的官方文檔中的定義是這樣的:

apply:Calls the specified function block with this value as its receiver and returns this value.

我們來看下他的實(shí)現(xiàn)代碼:

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }

這里結(jié)合前面的函數(shù)相關(guān)概念,對(duì)這個(gè)方法進(jìn)行分析:

apply為高階函數(shù),它接受一個(gè)參數(shù)block,類型為 T.() -> Unit,在apply的函數(shù)體內(nèi),調(diào)用了傳入的block這個(gè)函數(shù),然后返回調(diào)用apply函數(shù)的對(duì)象實(shí)例。

需要注意的是,block函數(shù)的類型為 function-with-receiver ,在block函數(shù)體內(nèi),可以通過this訪問到T類型的實(shí)例。

//調(diào)用方法
fun getDeveloper(): Developer {
    return Developer().apply {
        developerName = "Amit Shekhar"
        developerAge = 22
    }
}
// 等同于下面這個(gè)方法
fun getDeveloper(): Developer {
    //apply 方法返回新創(chuàng)建的Developer()
    return Developer().apply {
        //this 為新創(chuàng)建的Developer(),可省略
        this.developerName = "Amit Shekhar"
        this.developerAge = 22
    }
}

with

with也是比較常用的方法,它的定義是這樣的:

Calls the specified function block with the given receiver as its receiver and returns its result.

它的實(shí)現(xiàn)代碼也只有一行

public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()

with為高階函數(shù),接收兩個(gè)參數(shù):receiver,類型為T,block 類型為 T.() -> R,為function-with-receiver type,只能被T類型的對(duì)象調(diào)用,同樣,在block方法體內(nèi),可以通過this來調(diào)用到receiver。with返回的類型為R,和block的返回類型相同

fun getPersonFromDeveloper(developer: Developer): Person {
    return with(developer) {
        Person(developerName, developerAge)
    }
}

參考:
learn kotlin apply vs with
what is a receiver in kotlin
What is a purpose of Lambda's with Receiver?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容