Kotlin(1.1)學習筆記(11)——內聯函數

我們知道在函數在編譯器中都有自己的內存地址,我們在運行程序時每遇到一個函數調用都會進行:地址跳轉->執行->返回。這種轉移操作要求在轉去前要保護現場并記憶執行的地址,轉回后先要恢復現場,并按原來保存地址繼續執行。也就是通常說的壓棧和出棧。因此,函數調用要有一定的時間和空間方面的開銷。對于那些函數體代碼不是很大,又頻繁調用的函數來說,這個時間和空間的消耗會很大。
內聯函數就是為了解決這個問題而出現。所謂內聯函數就是在程序編譯時,編譯器將程序中出現的內聯函數的表達式整合到函數被調用的地方去,從而生成的代碼內存地址是連續的,減少了壓棧/出棧的時間。實際就是用空間換時間的一個策略。

inline 內聯

如果上面的解釋沒看懂的話,看代碼:

fun lock<T>(lock: Lock, body: () -> T): T {
  ...
  body()
  ...
}

這個函數在編譯時會出現兩個代碼段(也就是兩個內存地址):
1.lock函數 : 0xXXXXXXXX;
2.body的實際函數:0xYYYYYYYYY;
如果使用內聯

inline fun lock<T>(lock: Lock, body: () -> T): T {
  ...
   body()
  ...
}

則lock函數中調用body()的地方會被body函數體代替,最后只生成了一個連續的內存地址
lock函數 : 0xZZZZZZZZ;

noinline 禁用內聯

如果一個內聯函數的參數中有多個 Lambda 表達式, 而你只希望內聯其中的一部分, 你可以對函數的一部分參數添加 noinline 標記:

inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) {
    // ...
}

這樣的話,lambda:inlined是內聯,lambda:notInlined就是非內聯

非局部返回

在上一章中的限定的返回中我們只是簡單的介紹了如何使用,這里就仔細的說一下。
kotlin中使用無限定符的return語句只能用來退出一個普通函數或者匿名函數(也就是fun定義的函數),如果我們想要退出lambda表達式必須使用一個標簽。
繼續使用上一章中的lock函數:

 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函數。比如我們在循環中使用的return就是這種。

for (item in list){
    if (item==2){
           return
     }
}

crossinline

一些內聯函數可能調用傳給它們的不是直接來自函數體、而是來自另一個執行 上下文的 lambda 表達式參數,例如來自局部對象或嵌套函數。在這種情況下,該 lambda 表達式中 也不允許非局部控制流。為了標識這種情況,該 lambda 表達式參數需要 用 crossinline 修飾符標記:

inline fun f(crossinline body: () -> Unit) {
    val f = object: Runnable {
        override fun run() = body()
    }
    // ……
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容