首發(fā)于公眾號(hào): DSGtalk1989
20.內(nèi)聯(lián)函數(shù)
-
關(guān)鍵字inline
高階函數(shù)需要傳入的函數(shù)參數(shù)最終都會(huì)通過(guò)對(duì)象的方式去使用,而為了提升性能,我們需要使用
inline
關(guān)鍵字去修飾內(nèi)聯(lián)函數(shù),內(nèi)聯(lián)函數(shù)可以直接將方法體編譯至調(diào)用處。//kotlin fun notInlineFun(){ val a = 1L val b = "123" } inline fun inlineFun(){ val c = 2L val d = "456" } fun main() { notInlineFun() inlineFun() } //decompiled public final class InlineTestKt { public static final void notInlineFun() { long a = 1L; String b = "123"; } public static final void inlineFun() { int $i$f$inlineFun = 0; long c = 2L; String d = "456"; } public static final void main() { notInlineFun(); int $i$f$inlineFun = false; long c$iv = 2L; String var3 = "456"; } // $FF: synthetic method public static void main(String[] var0) { main(); } }
我們可以看到,
inlineFun
中的函數(shù)內(nèi)容全部被編譯復(fù)制到了main
方法中。
-
到底什么時(shí)候內(nèi)聯(lián)
我們?cè)谏厦娴睦又?,?huì)發(fā)現(xiàn)kotlin給出了一個(gè)提示
expected performance impact of inlining is insignificant. Inlining works best for functions with parameters of functional types
直接這樣使用
inline
對(duì)于性能的影響微乎其微,建議將inline
和lambda表達(dá)式結(jié)合起來(lái)用,即官方建議我們將內(nèi)聯(lián)函數(shù)使用在高階函數(shù)中。那么是否我們所有的高階函數(shù)為了提高性能都可以直接使用
inline
來(lái)進(jìn)行就修飾了呢,也不盡然。目前看來(lái)內(nèi)聯(lián)函數(shù)由于是代碼拷貝的方式,本身提高性能的同時(shí),可以進(jìn)行代碼內(nèi)
return
。首先我們來(lái)看一下,沒(méi)有用inline形容的高階函數(shù)。
fun html( a : (String) -> Unit){ a.invoke("abc") a("def") }
如果我們想要跳出的話,需要加入標(biāo)簽才能跳出,并且只是單單針對(duì)函數(shù)體的返回類型
Unit
的函數(shù),同時(shí)只能跳出函數(shù)體。html { return@html }
而比如我們有這樣一個(gè),如果給到的
String
不是我們需要的那個(gè),我們希望直接跳出包含調(diào)用函數(shù)的函數(shù)體,而不是單單跳出html
函數(shù),及如下的效果fun main(){ html { if(it.startWith("a")){ println("failed") //希望此處退出,并且連下面的success也不答應(yīng)出來(lái) } } println("success") }
這時(shí)候我們就不得不用內(nèi)聯(lián)函數(shù)來(lái)進(jìn)行處理,由于內(nèi)聯(lián)函數(shù)是整個(gè)函數(shù)的拷貝進(jìn)入,就是等于把整個(gè)lambda函數(shù)原封不動(dòng)的拷貝到調(diào)用所在地。所以
return
就能跳出調(diào)用函數(shù)的函數(shù)體fun main(){ html { if(it.startsWith("a")){ println("failed") return } } println("success") }
目前的kotlin版本中暫時(shí)不支持
break
和continue
-
crossinline和noinline
在高階函數(shù)中,我們用
noinline
關(guān)鍵字和crossinline
來(lái)修飾lambda表達(dá)式,首先這兩個(gè)表達(dá)式都不允許進(jìn)行return
,不一樣的是noinline
是徹底的不進(jìn)行拷貝,而crossinline
依然是拷貝的,只是不允許return
使用
inline
修飾的高階函數(shù),默認(rèn)參數(shù)函數(shù)都是直接內(nèi)聯(lián)拷貝的。
-
實(shí)體化類型參數(shù)reified
有時(shí)候我們只是單單需要使用一下類型,即java中的
classType
,比如說(shuō)如果這個(gè)傳參是什么類型的話,那我們就做不同的處理。一般情況下我們會(huì)這樣處理。fun <T> doSomeThing(a : T) : Unit{ if(a is String){ println("is String") } println("is Other") } fun <T> doSomeThing(clazz : Class<T>) : Unit{ if(clazz.isInstance(String)){ println("is String") } println("is Other") }
這種情況通常我們?cè)谡{(diào)用的時(shí)候都會(huì)省去
<>
,因?yàn)橄到y(tǒng)都可以幫我們判斷出來(lái)是什么類型。那么我們?cè)賮?lái)看一下這樣一種情況,類
A
中有一個(gè)b
屬性,我們需要看下這個(gè)b
是否是某個(gè)屬性。class A{ val b = Any() } fun <T> A.bIsType(clazz : Class<T>){ if(clazz.isInstance(b)){ println("get it") } } fun main() { val a = A() a.bIsType(String::class.java) }
我們生成了一個(gè)
A
的擴(kuò)展函數(shù),傳入一個(gè)類型參數(shù),然后判斷一下b是不是我們需要的那個(gè)類型。換一種方式,我們希望直接可以直接把泛型的類型拿來(lái)用,而不是需要傳入具體的
Class
,這樣我們就不需要往里面?zhèn)魅刖唧w的對(duì)象了,直接通過(guò)<String>
的方式,這里我們就需要使用到reified
為什么要放在內(nèi)聯(lián)函數(shù)中介紹呢,因?yàn)?code>reified關(guān)鍵字只會(huì)和
inline
一起出現(xiàn),修改后為如下inline fun <reified T> A.bIsType(){ if(b is T){ println("get it") } } fun main() { val a = A() a.bIsType<String>() }
這樣一來(lái),泛型T可以直接當(dāng)成類型對(duì)象來(lái)使用,相當(dāng)?shù)姆奖恪?/p>
-
內(nèi)聯(lián)屬性
屬性有
get
和set
的方法,如果這兩個(gè)方法中并沒(méi)有涉及到field
的復(fù)雜運(yùn)算,我們也可以將屬性相應(yīng)的用inline
進(jìn)行修飾,我們可以直接修飾屬性,或者修飾屬性的get
或者set
方法。val foo: Foo inline get() = Foo() var bar: Bar get() = ... inline set(v) { ... } inline var bar: Bar get() = ... set(v) { ... }
具體在什么地方使用,暫時(shí)還沒(méi)有參透。。
Kotlin學(xué)習(xí)筆記之 1 基礎(chǔ)語(yǔ)法
Kotlin學(xué)習(xí)筆記之 2 基本數(shù)據(jù)類型
Kotlin學(xué)習(xí)筆記之 4 循環(huán)控制
Kotlin學(xué)習(xí)筆記之 5 類和對(duì)象
Kotlin學(xué)習(xí)筆記之 8 擴(kuò)展
Kotlin學(xué)習(xí)筆記之 9 數(shù)據(jù)類與密封類
Kotlin學(xué)習(xí)筆記之 12 對(duì)象表達(dá)式和對(duì)象聲明
Kotlin學(xué)習(xí)筆記之 13 基礎(chǔ)操作符run、with、let、also、apply
Kotlin學(xué)習(xí)筆記之 14 包與導(dǎo)入
Kotlin學(xué)習(xí)筆記之 15 伴生對(duì)象
Kotlin學(xué)習(xí)筆記之 18 函數(shù)
Kotlin學(xué)習(xí)筆記之 19 高階函數(shù)與 lambda 表達(dá)式
Kotlin學(xué)習(xí)筆記之 20 內(nèi)聯(lián)函數(shù)
Kotlin學(xué)習(xí)筆記之 21 解構(gòu)聲明
Kotlin學(xué)習(xí)筆記之 28 協(xié)程基礎(chǔ)
Kotlin學(xué)習(xí)筆記之 29 上下文與調(diào)度器
Kotlin學(xué)習(xí)筆記之 30 協(xié)程取消與超時(shí)
Kotlin學(xué)習(xí)筆記之 31 協(xié)程掛起函數(shù)的組合