您好,登錄后才能下訂單哦!
Kotlin 內聯函數詳解及實例
概述
在說內聯函數之前,先說說函數的調用過程。
調用某個函數實際上將程序執行順序轉移到該函數所存放在內存中某個地址,將函數的程序內容執行完后,再返回到轉去執行該函數前的地方。這種轉移操作要求在轉去前要保護現場并記憶執行的地址,轉回后先要恢復現場,并按原來保存地址繼續執行。也就是通常說的壓棧和出棧。因此,函數調用要有一定的時間和空間方面的開銷。那么對于那些函數體代碼不是很大,又頻繁調用的函數來說,這個時間和空間的消耗會很大。
那怎么解決這個性能消耗問題呢,這個時候需要引入內聯函數了。內聯函數就是在程序編譯時,編譯器將程序中出現的內聯函數的調用表達式用內聯函數的函數體來直接進行替換。顯然,這樣就不會產生轉去轉回的問題,但是由于在編譯時將函數體中的代碼被替代到程序中,因此會增加目標程序代碼量,進而增加空間開銷,而在時間代銷上不象函數調用時那么大,可見它是以目標代碼的增加為代價來換取時間的節省。
inline
在Kotlin中,使用inline修飾符標記內聯函數,既會影響到函數本身, 也影響到傳遞給它的Lambda表達式,這兩者都會被內聯到調用處。
例如:
inline fun lock<T>(lock: Lock, body: () -> T): T { // ... }
編譯器可以直接產生下面的代碼, 而不必為參數創建函數對象, 然后再調用這個參數指向的函數:
l.lock() try { foo() } finally { l.unlock() }
noinline
如果一個內聯函數的參數中有多個 Lambda 表達式, 而你只希望內聯其中的一部分, 你可以對函數的一部分參數添加 noinline 標記:
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { // ... }
可內聯的 Lambda 表達式只能在內聯函數內部調用, 或者再作為可內聯的參數傳遞給其他函數, 但noinline 的 Lambda 表達式可以按照我們喜歡的方式任意使用: 可以保存在域內, 也可以當作參數傳遞, 等等。
非局部返回(Non-local return)
在Kotlin中, 使用無限定符的通常的return語句, 只能用來退出一個有名稱的函數, 或匿名函數. 這就意味著, 要退出一個Lambda表達式, 我們必須使用一個 標簽, 無標簽的 return 在 Lambda 表達式內是禁止使用的, 因為 Lambda 表達式不允許強制包含它的函數返回:
fun foo() { ordinaryFunction { return // 錯誤: 這里不允許讓 `foo` 函數返回 } }
如果 Lambda 表達式被傳遞去的函數是內聯函數, 那么 return 語句也可以內聯, 因此 return 是允許的。
fun foo() { inlineFunction { return // OK: 這里的 Lambda 表達式是內聯的 } }
注:
有些內聯函數可能并不在自己的函數體內直接調用傳遞給它的 Lambda 表達式參數, 而是通過另一個執行環境來調用, 比如通過一個局部對象, 或者一個嵌套函數. 這種情況下, 在 Lambda 表達式內, 非局部的控制流同樣是禁止的. 為了標識這一點, Lambda 表達式參數需要添加 crossinline修飾符。
inline fun f(crossinline body: () -> Unit) { val f = object: Runnable { override fun run() = body() } // ... }
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。