我們知道在函數(shù)在編譯器中都有自己的內(nèi)存地址惭聂,我們?cè)谶\(yùn)行程序時(shí)每遇到一個(gè)函數(shù)調(diào)用都會(huì)進(jìn)行:地址跳轉(zhuǎn)->執(zhí)行->返回冻璃。這種轉(zhuǎn)移操作要求在轉(zhuǎn)去前要保護(hù)現(xiàn)場(chǎng)并記憶執(zhí)行的地址捏悬,轉(zhuǎn)回后先要恢復(fù)現(xiàn)場(chǎng)修然,并按原來(lái)保存地址繼續(xù)執(zhí)行戈毒。也就是通常說(shuō)的壓棧和出棧硼啤。因此议经,函數(shù)調(diào)用要有一定的時(shí)間和空間方面的開(kāi)銷(xiāo)。對(duì)于那些函數(shù)體代碼不是很大谴返,又頻繁調(diào)用的函數(shù)來(lái)說(shuō)煞肾,這個(gè)時(shí)間和空間的消耗會(huì)很大。
內(nèi)聯(lián)函數(shù)就是為了解決這個(gè)問(wèn)題而出現(xiàn)嗓袱。所謂內(nèi)聯(lián)函數(shù)就是在程序編譯時(shí)籍救,編譯器將程序中出現(xiàn)的內(nèi)聯(lián)函數(shù)的表達(dá)式整合到函數(shù)被調(diào)用的地方去,從而生成的代碼內(nèi)存地址是連續(xù)的索抓,減少了壓棧/出棧的時(shí)間钧忽。實(shí)際就是用空間換時(shí)間的一個(gè)策略。
inline 內(nèi)聯(lián)
如果上面的解釋沒(méi)看懂的話(huà)逼肯,看代碼:
fun lock<T>(lock: Lock, body: () -> T): T {
...
body()
...
}
這個(gè)函數(shù)在編譯時(shí)會(huì)出現(xiàn)兩個(gè)代碼段(也就是兩個(gè)內(nèi)存地址):
1.lock函數(shù) : 0xXXXXXXXX;
2.body的實(shí)際函數(shù):0xYYYYYYYYY;
如果使用內(nèi)聯(lián)
inline fun lock<T>(lock: Lock, body: () -> T): T {
...
body()
...
}
則lock函數(shù)中調(diào)用body()的地方會(huì)被body函數(shù)體代替耸黑,最后只生成了一個(gè)連續(xù)的內(nèi)存地址
lock函數(shù) : 0xZZZZZZZZ;
noinline 禁用內(nèi)聯(lián)
如果一個(gè)內(nèi)聯(lián)函數(shù)的參數(shù)中有多個(gè) Lambda 表達(dá)式, 而你只希望內(nèi)聯(lián)其中的一部分, 你可以對(duì)函數(shù)的一部分參數(shù)添加 noinline 標(biāo)記:
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
// ...
}
這樣的話(huà),lambda:inlined是內(nèi)聯(lián)篮幢,lambda:notInlined就是非內(nèi)聯(lián)
非局部返回
在上一章中的限定的返回中我們只是簡(jiǎn)單的介紹了如何使用大刊,這里就仔細(xì)的說(shuō)一下。
kotlin中使用無(wú)限定符的return語(yǔ)句只能用來(lái)退出一個(gè)普通函數(shù)或者匿名函數(shù)(也就是fun
定義的函數(shù))三椿,如果我們想要退出lambda表達(dá)式必須使用一個(gè)標(biāo)簽缺菌。
繼續(xù)使用上一章中的lock函數(shù):
fun<T> lock(body: ()->T): T{
val lock = Any()
synchronized(lock){
return body()
}
}
inline fun<T> inlineLock(body: ()->T): T{
val lock = Any()
synchronized(lock){
return body()
}
}
inlineLock
的lambda中這種返回就被成為局部返回。他會(huì)直接跳出整個(gè)inlineLock函數(shù)搜锰。比如我們?cè)谘h(huán)中使用的return就是這種伴郁。
for (item in list){
if (item==2){
return
}
}
crossinline
一些內(nèi)聯(lián)函數(shù)可能調(diào)用傳給它們的不是直接來(lái)自函數(shù)體、而是來(lái)自另一個(gè)執(zhí)行 上下文的 lambda 表達(dá)式參數(shù)蛋叼,例如來(lái)自局部對(duì)象或嵌套函數(shù)焊傅。在這種情況下,該 lambda 表達(dá)式中 也不允許非局部控制流狈涮。為了標(biāo)識(shí)這種情況狐胎,該 lambda 表達(dá)式參數(shù)需要 用 crossinline 修飾符標(biāo)記:
inline fun f(crossinline body: () -> Unit) {
val f = object: Runnable {
override fun run() = body()
}
// ……
}