Kotlin 高階函數、內聯

2021-02-14 code日常

例如剛才的高階函數的例子:

我們來看下編譯後的 class 文件:


從編譯文件看到,剛才的高階函數調用處被編譯成了 Function0 的類型,因為我們的高階函數那裡沒有參數,所以是 0,如果是 個參數就是 Function1,系統最多提供了 22 個參數,再多的就需要自己定義擴展了。

好傢夥,那我們如果來個 for  循環,那不是創建了一堆實例對象?這時候 inline  就可以起作用了,編譯的時候直接把調用代碼複製替換進去。

我們來修改一下,加個 inline 關鍵字在看下效果:

然後再次編譯下看看:

可以看到,直接把原本的調用 copy 到調用處了。這樣就不會編譯為 FunctionX  類,減少了運行時的對象創建開銷。

那我是不是可以全部都弄成內聯了?但是這樣就又有了個問題。

在 println 加了個 return ,這樣就會導致下面的列印 「運行完成2」和「結束」都無法運行,這很明顯不是我們想要的,解決方法也很簡單,我們在 return 處加個 @label 就可以了。

不過 Kotlin 也有另一種方式來限制在 lambda 中直接 return,那就是使用 noinline 或 crossinline 。

如果你只是想內聯函數的某些 lamda  表達式被內聯,其他的不允許內聯操作的話可以使用 noinline 。

如上圖,middle 加了 noinline 後,return 報錯了,已經不能直接進行 return 操作,return@label 還是可以的。

那問題又來了,直接改成 noinline 的話,那不是又變成搞了一堆對象出來了?還有沒其他方法?Kotlin 還提供了一個 crossline 關鍵字。

把上面的 noinline 的例子改成 crossline ,來對比下編譯後的文件

從上面可以看得出,crossline  不會搞出一堆對象。

為了減少使用高階函數帶來的一些運行時的效率損失,可以使用inline 來標記一個函數為內聯函數。

內聯函數在編譯後會把代碼都插入到調用函數的地方,所以可能導致最終的代碼增加,所以必須避免內聯過大函數才能使內聯函數性能提升。

另外我們可以用 noinline 和 crossinline 來限制內聯函數中的lambda 直接調用 return 返回,避免出現預料之外的結果。

剛才我提到了編譯後的文件,那麼在 AndroidStudio 上如何快速查看呢?

相關焦點

  • Kotlin最佳實踐:在高階函數中使用inline - 碼農登陸
    前言最近,無意中看到一篇文章,是聊inline在高階函數中的性能提升,說實話之前沒有認真關注過這個特性,所以藉此機會好好學習了一番。高階函數:入參中含有lambda的函數(方法)。也算是技術無國界吧,哈哈~官方文檔對inline的使用主要提供了倆種方式:內聯類、內聯函數正文操作符是我們日常Kotlin開發的利器,如果我們點進去看看源碼,我們會發現這些操作符大多都會使用inline。
  • Kotlin函數式編程
    那麼在函數式編程中當然一切皆是函數。在Kotlin中函數式的地位和對象一樣高,你可以在方法中輸入函數,也可以返回函數。函數式編程FP特徵:函數式編程核心概念:函數是「一等公民」:是指函數與其他數據類型是一樣的,處於平等地位。函數可以作為其他函數的參數傳入,也可以作為其他函數的返回值返回。
  • 幾個特性,快速上手Kotlin
    不不不,往下看,kotlin中的屬性大有文章。1.1、可觀察屬性Observable這個語言特性,是非常非常用意思,且實用的。不信?因為forEach內聯函數。內聯函數是可以return的:關於內聯函數後文會有篇幅展開它。官方介紹:內聯是被允許的(這種返回(位於 lambda 表達式中,但退出包含它的函數)稱為非局部返回。)
  • Kotlin入門教程,快使用Kotlin吧
    學習網站 Kotlin 從入門到放棄:https://www.jianshu.com/c/d3eac4c37b5fKotlin 菜鳥教程:http://www.runoob.com/kotlin/kotlin-tutorial.html基本語法 1、數據類型1.1、基本數據類型類型位寬度Double64Float32Long64Int32Short16Byte8每一個類型都有一個toXXX
  • 內聯函數和外聯函數有什麼區別
    內聯函數   內聯函數是指用inline關鍵字修飾的函數。在類內定義的函數被默認成內聯函數。內聯函數從原始碼層看,有函數的結構,而在編譯後,卻不具備函數的性質。   內聯函數不是在調用時發生控制轉移,而是在編譯時將函數體嵌入在每一個調用處。編譯時,類似宏替換,使用函數體替換調用處的函數名。一般在代碼中用inline修飾,但是能否形成內聯函數,需要看編譯器對該函數定義的具體處理。   內聯擴展是用來消除函數調用時的時間開銷。
  • 新手入門:關於C++中的內聯函數(inline)
    正在閱讀:新手入門:關於C++中的內聯函數(inline)新手入門:關於C++中的內聯函數(inline)2005-03-01 10:10出處:PConline作者:管寧>   在c++中,為了解決一些頻繁調用的小函數大量消耗棧空間或者是叫棧內存的問題,特別的引入了inline修飾符,表示為內聯函數。
  • Kotlin 怎麼學 ?遇到過哪些坑?
    那麼常規的 java 代碼,寫起來可能就是一堆的回調,但是使用 kotlin 的 擴展函數+代理,封裝之後,你看到的就是下面一行代碼。等可空類型,類似 java 操作是 先要判斷該對象是否為該類型,然後強轉,語法比較繞,然而 kotlin 直接支持可為空類型的轉換5.functions and lambdas - 函數和 lambdas 表達式在 kotlin 裡面函數是第一公民,java 8 也把加入了該特性,但是遠遠沒有 kotlin 的函數功能強大,kotlin 的函數功能如下
  • Kotlin 中的 inline ,noinline 和 crossinline
    佛系編碼  ·  寫點編碼的日常inline  在編譯時,會將此修飾符修飾的函數複製到調用處(稱為內聯),避免創建 Function 對象,以減少創建對象的內存開銷。noinline 需要配合 inline 使用,使用在函數型參上,告訴編譯器當前這個函數不能內聯crossinline 需要配合 inline 使用,告訴編譯器不能使用 return,否則就跳出調用處函數,但是可以使用 return@label 跳出指定外層。
  • C++ 宏替換和內聯函數的區別
    先說基礎知識,宏替換發生在的是預編譯階段、內聯函數發生在的是運行階段。
  • Python基礎教程——高階函數
    Python的高階函數,就是map、filter、reduce,說它們是高階函數,只是因為我們平時用的少,所以理解起來也有點費勁,事實上,它們功能很強大,也很好用易用。一起來看看吧。平方函數例1:多個數字組成的一個列表,我們想要對每個數字都乘以2,雖然使用for循環也能完成,但是明顯太繁瑣,使用map這個高階函數,就簡單多了。代碼如下:
  • Kotlin使用指南之類篇特殊的類
    - 密封類不允許有非-private 構造函數(其構造函數默認為 private)。- 密封類子類的子類可以放在任何位置,而無需在同一個文件中。可以使用 enumValues\<T>() 與 enumValueOf\<T>() 函數以泛型的方式訪問枚舉類中的常量,結合上面的代碼```KOTLINprint(enumValues<Color>().joinToString { it.name })```對象kotlin中的對象關鍵字
  • vlookup函數的高階學習,對參數的處理技巧
    我們在實際工作中,我們經常使用excel表格處理和分析數據,我們為了提高工作效率,我們通常會在平時積累各種各樣的實用小技巧,我們這次還是分享有關查找函數的使用技巧。我們之前學習過vlookup函數的基礎操作技能,這次我們學習一下vlookup函數的高階技能,有關對vlookup函數參數的處理小技巧,下面我們就一起學習一下。
  • Kotlin學習筆記——基礎篇
    1.基礎語法英文官網:https://kotlinlang.org/docs/reference/中文官網:https://www.kotlincn.net/docs/reference/協程學習資料:https://www.kotlincn.net/docs/reference/coroutines-overview.html
  • 最強總結 | 帶你快速搞定kotlin開發(上篇)
    fun sum(a: Int, b: Int): Int {     return a + b}  // 對於只有一行的函數,kotlin可以這麼簡寫,爽不?注意加上(),如果你的kotlin類能夠被繼承,需要使用open關鍵字,因為默認是final的:open class Person {    constructor(age: Int)    var age: Int = 0}// 當你的構造函數調用父類的構造函數時,要去掉Person
  • 你真的懂 JavaScript 閉包與高階函數嗎?
    高階函數高階函數就是輸入參數裡有函數,或者輸出是函數的函數。2.1 函數作為參數如果你用過 setTimeout、setInterval、ajax 請求,那麼你已經用過高階函數了,這是我們最常看到的場景:回調函數,因為它將函數作為參數傳遞給另一個函數。
  • 一些 Kotlin 小技巧及解析
    結合著 Kotlin 的高級函數的特性可以讓代碼可讀性更強,更加簡潔,但是呢簡潔的背後是有代價的,使用不當對性能可能會有損耗,這塊往往很容易被我們忽略,這就需要我們去研究 kotlin 語法糖背後的魔法,當我們在開發的時候,選擇合適的語法糖,儘量避免這些錯誤,關於 Kotlin 性能損失那些事,可以看一下我另外兩篇文章。
  • 問:談談 Kotlin 範型與逆變協變?
    kotlin 系列文章均以 Java 差異為核心進行提煉,與 Java 相同部分不再列出。隨著 kotlin 官方版本的迭代,文中有些語法可能會發生變化,請務必留意。kotlin 泛型(generics)與 java 一樣,kotlin 的泛型用來表示變量類型的參數化。
  • Kotlin Vocabulary | 內聯類 inline class
    根據您比較兩個內聯類結構的方式的不同,會最終造成 (內聯類) 其中一個參數被裝箱,也或者所有參數都不會被裝箱。為了實現此功能,Kotlin 編譯器會改寫函數的名稱,並使用內聯類作為函數參數。我們已經講過,不能在 Java 中實例化內聯類。那可不可以使用呢?✅ 可以將內聯類傳遞給 Java 函數我們可以將內聯類作為參數傳遞,它們將會作為對象被使用。
  • 使用 Kotlin 進行 Android 測試
    Kotlin 是函數式。 Functions and properties 是第一公民。Kotlin 是友好的。Kotlin 和 Java 幾乎可以完美共存。為什麼要在測試中使用 Kotlin?我們有一個使用 Java 寫的 Android 代碼庫,我們想逐步引入這門帥氣的語言,所以為啥不從測試開始呢?
  • n階即高階導數計算舉例解析
    一階導數的導數稱為二階導數,二階以上的導數可由歸納法逐階定義,二階和二階以上的導數統稱為高階導數,本文主要介紹三階以上導數計算規律。例題解析n 階導數:萊布尼茲公式設函數u(x)、v(x)在點x都具有 n 階導數,則由一階導數乘積的運算法則有:[u(x)*v(x)]'=u'(x)v(x)+u(x)v'(x);二階導數乘積的運算法則有