我們知道在函數(shù)在編譯器中都有自己的內存地址,我們在運行程序時每遇到一個函數(shù)調用都會進行:地址跳轉->執(zhí)行->返回。這種轉移操作要求在轉去前要保護現(xiàn)場并記憶執(zhí)行的地址,轉回后先要恢復現(xiàn)場,并按原來保存地址繼續(xù)執(zhí)行。也就是通常說的壓棧和出棧。因此,函數(shù)調用要有一定的時間和空間方面的開銷。對于那些函數(shù)體代碼不是很大,又頻繁調用的函數(shù)來說,這個時間和空間的消耗會很大。
內聯(lián)函數(shù)就是為了解決這個問題而出現(xiàn)。所謂內聯(lián)函數(shù)就是在程序編譯時,編譯器將程序中出現(xiàn)的內聯(lián)函數(shù)的表達式整合到函數(shù)被調用的地方去,從而生成的代碼內存地址是連續(xù)的,減少了壓棧/出棧的時間。實際就是用空間換時間的一個策略。
inline 內聯(lián)
如果上面的解釋沒看懂的話,看代碼:
fun lock<T>(lock: Lock, body: () -> T): T {
...
body()
...
}
這個函數(shù)在編譯時會出現(xiàn)兩個代碼段(也就是兩個內存地址):
1.lock函數(shù) : 0xXXXXXXXX;
2.body的實際函數(shù):0xYYYYYYYYY;
如果使用內聯(lián)
inline fun lock<T>(lock: Lock, body: () -> T): T {
...
body()
...
}
則lock函數(shù)中調用body()的地方會被body函數(shù)體代替,最后只生成了一個連續(xù)的內存地址
lock函數(shù) : 0xZZZZZZZZ;
noinline 禁用內聯(lián)
如果一個內聯(lián)函數(shù)的參數(shù)中有多個 Lambda 表達式, 而你只希望內聯(lián)其中的一部分, 你可以對函數(shù)的一部分參數(shù)添加 noinline 標記:
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
// ...
}
這樣的話,lambda:inlined是內聯(lián),lambda:notInlined就是非內聯(lián)
非局部返回
在上一章中的限定的返回中我們只是簡單的介紹了如何使用,這里就仔細的說一下。
kotlin中使用無限定符的return語句只能用來退出一個普通函數(shù)或者匿名函數(shù)(也就是fun定義的函數(shù)),如果我們想要退出lambda表達式必須使用一個標簽。
繼續(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中這種返回就被成為局部返回。他會直接跳出整個inlineLock函數(shù)。比如我們在循環(huán)中使用的return就是這種。
for (item in list){
if (item==2){
return
}
}
crossinline
一些內聯(lián)函數(shù)可能調用傳給它們的不是直接來自函數(shù)體、而是來自另一個執(zhí)行 上下文的 lambda 表達式參數(shù),例如來自局部對象或嵌套函數(shù)。在這種情況下,該 lambda 表達式中 也不允許非局部控制流。為了標識這種情況,該 lambda 表達式參數(shù)需要 用 crossinline 修飾符標記:
inline fun f(crossinline body: () -> Unit) {
val f = object: Runnable {
override fun run() = body()
}
// ……
}