kotlin學習之inline、noinline和crossinline

首先說結(jié)論,

inline:通過內(nèi)聯(lián)(即函數(shù)內(nèi)容直接插入到調(diào)用處)的方式來編譯,用于方法

noinline:局部關(guān)掉這個優(yōu)化,來擺脫不能把函數(shù)類型的參數(shù)當做對象使用的限制,用于參數(shù)

crossinline:局部加強內(nèi)聯(lián)優(yōu)化,讓內(nèi)聯(lián)函數(shù)里的函數(shù)類型的參數(shù)可以間接被調(diào)用,代價是不能在Lambda表達式里使用return,用于參數(shù)

inline

首先我們定義一個方法,然后在main函數(shù)里面調(diào)用

fun hello(postAction:() -> Unit){
    println("Hello")
    postAction()
}

fun main(){
    hello{
        println("Bye")
    }
}

那在實際編譯的過程是這樣的

fun main(){
    val post = object : Function<Unit>{
        override fun invoke(){
            return println("Bye")
        }
    }
    hello(post)
}

可以看到在kotlin中,用一個jvm的對象來作為函數(shù)的變量的實際載體,讓這個對象去執(zhí)行實際代碼,也就是說生成一個對象去執(zhí)行Lambda表達式里的代碼時,但是這個對象用完就回收了,一兩處調(diào)用可能并沒有什么影響,但是放在一個循環(huán)體調(diào)用,這樣內(nèi)存占用會一下就飚起來。

這個時候inline就有很大用處了,首先修改一下hello方法,然后在main方法中繼續(xù)調(diào)用

inline fun hello(postAction:() -> Unit){
    println("Hello")
    postAction()
}

fun main(){
    hello{
        println("Bye")
    }
}

這樣在實際編譯中就會是下面這種形式

fun main(){
    println("Hello")
    println("Bye")
}

這樣用內(nèi)聯(lián)的方式來減少對象的創(chuàng)建,從而避免性能問題,就不怕在循環(huán)體重調(diào)用了。

noinline

繼續(xù)對hello()進行改變。

inline fun hello(preAction:() -> Unit ,noinline postAction:() -> Unit){
    preAction()
    println("Hello")
    postAction()
}
fun main(){
    hello({
        println("Emm...")
    },{
        println("Bye")
    })
}

實際編譯的代碼大致為

fun main(){
    println("Emm...")
    println("Hello")
    ({
        println("Bye")
    }).invoke()
}

postAction這個參數(shù)則不會參與內(nèi)聯(lián)了。

運用場景:如果把某個參數(shù)作為返回值,因為前面用inline修飾,在實際使用是不會產(chǎn)生一個對象,而是即函數(shù)內(nèi)容直接插入到調(diào)用處,那這個時候我們返回,相當于返回一個不存在的對象。這樣就有問題了。

crossinline

首先需要知道一條規(guī)則:

Lambda表達式不允許使用return,除非這個Lambda表達式是內(nèi)聯(lián)函數(shù)的參數(shù)。
Lambda表達式不允許使用return,除非這個Lambda表達式是內(nèi)聯(lián)函數(shù)的參數(shù)。
Lambda表達式不允許使用return,除非這個Lambda表達式是內(nèi)聯(lián)函數(shù)的參數(shù)。
重要的事情說三遍。

首先來看個例子,

inline fun hello(postAction:() -> Unit){
    println("Hello")
    postAction()
}

fun main(){
    hello{
        println("Bye")
        return
    }
}

這個結(jié)果是return掉hello這個方法,還是return掉main這個方法?答案是main(),因為hello是內(nèi)聯(lián)函數(shù),所以被編譯之后會變成下面這樣,

fun main(){
    println("Hello")
    println("Bye")
    return
}

相當于Lambda表達式的return結(jié)束的不是直接的外層函數(shù),而是結(jié)束直接外層的外層函數(shù)。

那我們繼續(xù)對hello()進行修改如下:

inline fun hello(postAction:() -> Unit){
    println("Hello")
    runOnUiThread{
        postAction()
    }

}

相當于我們對postAction()這個外面有多包裹了一層,那這個時候又是怎樣的?

結(jié)果是這段代碼編譯通不過,因為內(nèi)聯(lián)函數(shù)里的函數(shù)類型的參數(shù)不允許這種間接調(diào)用。如果非要間接調(diào)用,那就需要用crossinline修飾這個參數(shù)。但是被crossinline修飾的函數(shù)類型參數(shù)將不再享有l(wèi)ambda表達式使用return的福利,也就是在main的hello()調(diào)用處將不能調(diào)用return.

inline fun hello(crossinline postAction:() -> Unit){
    println("Hello")
    runOnUiThread{
        postAction()
    }

}

fun main(){
    println("Hello")
    println("Bye")
    //return  不能調(diào)用return
}

這樣就可以間接調(diào)用了。

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

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