kotlin函數(shù)和Lambda表達(dá)式——>內(nèi)聯(lián)函數(shù)-創(chuàng)新互聯(lián)

1.內(nèi)聯(lián)函數(shù)kotlin函數(shù)和Lambda表
達(dá)式——>內(nèi)聯(lián)函數(shù)

使用高階函數(shù)會(huì)帶來(lái)一些運(yùn)行時(shí)的效率損失:每一個(gè)函數(shù)都是一個(gè)對(duì)象,并且會(huì)捕獲一個(gè)閉包。即那些 在函數(shù)體內(nèi)會(huì)訪問(wèn)到的變量。內(nèi)存分配(對(duì)于函數(shù)對(duì)象和類(lèi))和虛擬調(diào)用會(huì)引入運(yùn)行時(shí)間開(kāi)銷(xiāo)。

成都一家集口碑和實(shí)力的網(wǎng)站建設(shè)服務(wù)商,擁有專(zhuān)業(yè)的企業(yè)建站團(tuán)隊(duì)和靠譜的建站技術(shù),十余年企業(yè)及個(gè)人網(wǎng)站建設(shè)經(jīng)驗(yàn) ,為成都千余家客戶提供網(wǎng)頁(yè)設(shè)計(jì)制作,網(wǎng)站開(kāi)發(fā),企業(yè)網(wǎng)站制作建設(shè)等服務(wù),包括成都營(yíng)銷(xiāo)型網(wǎng)站建設(shè),品牌網(wǎng)站建設(shè),同時(shí)也為不同行業(yè)的客戶提供成都網(wǎng)站建設(shè)、成都網(wǎng)站設(shè)計(jì)的服務(wù),包括成都電商型網(wǎng)站制作建設(shè),裝修行業(yè)網(wǎng)站制作建設(shè),傳統(tǒng)機(jī)械行業(yè)網(wǎng)站建設(shè),傳統(tǒng)農(nóng)業(yè)行業(yè)網(wǎng)站制作建設(shè)。在成都做網(wǎng)站,選網(wǎng)站制作建設(shè)服務(wù)商就選創(chuàng)新互聯(lián)。

但是在許多情況下通過(guò)內(nèi)聯(lián)化 lambda 表達(dá)式可以消除這類(lèi)的開(kāi)銷(xiāo)。下述函數(shù)是這種情況的很好的例 子。即 lock() 函數(shù)可以很容易地在調(diào)用處內(nèi)聯(lián)??紤]下面的情況

lock(l) { foo() }

編譯器沒(méi)有為參數(shù)創(chuàng)建一個(gè)函數(shù)對(duì)象并生成一個(gè)調(diào)用。取而代之,編譯器可以生成以下代碼:

    l.lock() 
try {
        foo()
    }finally {
        l.unlock()
    }

為了讓編譯器這么做,我們需要使用 inline 修飾符標(biāo)記 lock() 函數(shù):

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

inline 修飾符影響函數(shù)本身和傳給它的 lambda 表達(dá)式:所有這些都將內(nèi)聯(lián)到調(diào)用處。

內(nèi)聯(lián)可能導(dǎo)致生成的代碼增加;不過(guò)如果我們使用得當(dāng)(即避免內(nèi)聯(lián)過(guò)大函數(shù)),性能上會(huì)有所提升,尤 其是在循環(huán)中的“超多態(tài)(megamorphic)”調(diào)用處。

2.禁用內(nèi)聯(lián)

如果希望只內(nèi)聯(lián)一部分傳給內(nèi)聯(lián)函數(shù)的 lambda 表達(dá)式參數(shù),那么可以用 noinline 修飾符標(biāo)記不希望內(nèi)聯(lián)的函數(shù)參數(shù)

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

可以?xún)?nèi)聯(lián)的 lambda 表達(dá)式只能在內(nèi)聯(lián)函數(shù)內(nèi)部調(diào)用或者作為可內(nèi)聯(lián)的參數(shù)傳遞,但是 noinline的可以以任何我們喜歡的方式操作:存儲(chǔ)在字段中、傳送它等等。

需要注意的是,如果一個(gè)內(nèi)聯(lián)函數(shù)沒(méi)有可內(nèi)聯(lián)的函數(shù)參數(shù)并且沒(méi)有具體化的類(lèi)型參數(shù),編譯器會(huì)產(chǎn)生一 個(gè)警告,因?yàn)閮?nèi)聯(lián)這樣的函數(shù)很可能并無(wú)益處(如果你確認(rèn)需要內(nèi)聯(lián),則可以用@Suppress("NOTHING_TO_INLINE") 注解關(guān)掉該警告)。

非局部返回

在 Kotlin 中,我們只能對(duì)具名或匿名函數(shù)使用正常的、非限定的 return 來(lái)退出。這意味著要退出一個(gè) lambda表達(dá)式,我們必須使用一個(gè)標(biāo)簽,并且在lambda表達(dá)式內(nèi)部禁止使用裸 return,因?yàn)閘ambda 表達(dá)式不能使包含它的函數(shù)返回:

fun foo() { 
    ordinaryFunction {
return // 錯(cuò)誤:不能使 `foo` 在此處返回    }
}

但是如果 lambda 表達(dá)式傳給的函數(shù)是內(nèi)聯(lián)的,該 return 也可以?xún)?nèi)聯(lián),所以它是允許的: inline fun inlined(block: () -> Unit) { println("hi!") }

fun foo() {
        inlined {
return // OK:該 lambda 表達(dá)式是內(nèi)聯(lián)的        }
    }
}

這種返回(位于 lambda 表達(dá)式中,但退出包含它的函數(shù))稱(chēng)為非局部返回。我們習(xí)慣了在循環(huán)中用這種結(jié)構(gòu),其內(nèi)聯(lián)函數(shù)通常包含

fun hasZeros(ints: List<Int>): Boolean {
     ints.forEach {
if (it == 0) return true // 從 hasZeros 返回     }
return false
}

請(qǐng)注意,一些內(nèi)聯(lián)函數(shù)可能調(diào)用傳給它們的不是直接來(lái)自函數(shù)體、而是來(lái)自另一個(gè)執(zhí)行上下文的 lambda 表達(dá)式參數(shù),例如來(lái)自局部對(duì)象或嵌套函數(shù)。在這種情況下,該 lambda 表達(dá)式中也不允許非局 部控制流。為了標(biāo)識(shí)這種情況,該 lambda 表達(dá)式參數(shù)需要用 crossinline 修飾符標(biāo)記:

 inline fun f(crossinline body: () -> Unit) {
        val f= object : Runnable {
override fun run() = body()
        }
// ......}

break和continue在內(nèi)聯(lián)的 lambda 表達(dá)式中還不可用,但我們也計(jì)劃支持它們。

3.具體化的類(lèi)型參數(shù)

有時(shí)候我們需要訪問(wèn)一個(gè)作為參數(shù)傳給我們的一個(gè)類(lèi)型:

fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
var p = parent
while (p != null && !clazz.isInstance(p)) {
        p= p.parent
    }
    @Suppress("UNCHECKED_CAST")
return p as T?
}

在這里我們向上遍歷一棵樹(shù)并且檢測(cè)每個(gè)節(jié)點(diǎn)是不是特定的類(lèi)型。這都沒(méi)有問(wèn)題,但是調(diào)用處不是很優(yōu)雅:

treeNode.findParentOfType(MyTreeNode::class.java)

我們真正想要的只是傳一個(gè)類(lèi)型給該函數(shù),即像這樣調(diào)用它

treeNode.findParentOfType<MyTreeNode>()

為能夠這么做,內(nèi)聯(lián)函數(shù)支持具體化的類(lèi)型參數(shù),于是我們可以這樣寫(xiě)

inline fun <reified T> TreeNode.findParentOfType(): T? {
var p = parent
while (p != null && p !is T) {
        p= p.parent
    }
return p as T?
}

我們使用 reified 修飾符來(lái)限定類(lèi)型參數(shù),現(xiàn)在可以在函數(shù)內(nèi)部訪問(wèn)它了,幾乎就像是一個(gè)普通的類(lèi) 一樣。由于函數(shù)是內(nèi)聯(lián)的,不需要反射,正常的操作符如 !is 和 as 現(xiàn)在都能用了。此外,我們還可以按 照上面提到的方式調(diào)用它:myTree.findParentOfType<MyTreeNodeType>() 。

雖然在許多情況下可能不需要反射,但我們?nèi)匀豢梢詫?duì)一個(gè)具體化的類(lèi)型參數(shù)使用它:

inline fun <reified T> membersOf() = T::class.members
fun main(s: Array<String>) {
    println(membersOf<StringBuilder>().joinToString("
"))
}

普通的函數(shù)(未標(biāo)記為內(nèi)聯(lián)函數(shù)的)不能有具體化參數(shù)。不具有運(yùn)行時(shí)表示的類(lèi)型(例如非具體化的類(lèi)型 參數(shù)或者類(lèi)似于 Nothing 的虛構(gòu)類(lèi)型)不能用作具體化的類(lèi)型參數(shù)的實(shí)參。

4.內(nèi)聯(lián)屬性(自1.1起)

inline 修飾符可用于沒(méi)有幕后字段的屬性的訪問(wèn)器。你可以標(biāo)注獨(dú)立的屬性訪問(wèn)器:

val foo: Foo
    inlineget() = Foo()
var bar: Bar 
get() = ......
    inlineset(v) { ...... }

你也可以標(biāo)注整個(gè)屬性,將它的兩個(gè)訪問(wèn)器都標(biāo)記為內(nèi)聯(lián)

inline var bar: Bar 
get() = ......
set(v) { ...... }

在調(diào)用處,內(nèi)聯(lián)訪問(wèn)器如同內(nèi)聯(lián)函數(shù)一樣內(nèi)聯(lián)

5.公有API內(nèi)聯(lián)函數(shù)的限制

當(dāng)一個(gè)內(nèi)聯(lián)函數(shù)是 public 或 protected 而不是 private 或 internal 聲明的一部分時(shí),就會(huì) 認(rèn)為它是一個(gè)模塊級(jí)的公有 API??梢栽谄渌K中調(diào)用它,并且也可以在調(diào)用處內(nèi)聯(lián)這樣的調(diào)用。

這帶來(lái)了一些由模塊做這樣變更時(shí)導(dǎo)致的二進(jìn)制兼容的?險(xiǎn)?聲明一個(gè)內(nèi)聯(lián)函數(shù)但調(diào)用它的模塊在 它修改后并沒(méi)有重新編譯。

為了消除這種由非公有 API 變更引入的不兼容的?險(xiǎn),公有 API 內(nèi)聯(lián)函數(shù)體內(nèi)不允許使用非公有聲明, 即,不允許使用 private 與 internal 聲明以及其部件。

一個(gè) internal 聲明可以由 @PublishedApi 標(biāo)注,這會(huì)允許它在公有 API 內(nèi)聯(lián)函數(shù)中使用。當(dāng)一 個(gè) internal 內(nèi)聯(lián)函數(shù)標(biāo)記有 @PublishedApi 時(shí),也會(huì)像公有函數(shù)一樣檢測(cè)其函數(shù)體。

文章名稱(chēng):kotlin函數(shù)和Lambda表達(dá)式——&gt;內(nèi)聯(lián)函數(shù)-創(chuàng)新互聯(lián)
網(wǎng)站路徑:http://bm7419.com/article34/gojse.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站制作、企業(yè)建站、網(wǎng)站內(nèi)鏈虛擬主機(jī)、網(wǎng)站維護(hù)、品牌網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)