在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Android/ Kotlin內(nèi)聯(lián)函數(shù)
Kotlin內(nèi)聯(lián)函數(shù)
Kotlin開發(fā)環(huán)境設(shè)置(Eclipse)
Kotlin調(diào)用Java代碼
Kotlin使用Ant
Kotlin編譯器插件
Kotlin相等性
Kotlin JavaScript模塊
編寫Kotlin代碼文檔
Kotlin返回和跳轉(zhuǎn)
Kotlin異常處理
Kotlin可見(jiàn)性修飾符
Kotlin委托
Kotlin委托屬性
Kotlin編碼約定/編碼風(fēng)格
Kotlin基礎(chǔ)語(yǔ)法
使用Kotlin進(jìn)行服務(wù)器端開發(fā)
Kotlin接口
Kotlin反射
Kotlin類型別名
Kotlin枚舉類
Kotlin當(dāng)前版本是多少?
Kotlin注解處理工具
Kotlin類型的檢查與轉(zhuǎn)換
Kotlin屬性和字段
Kotlin類型安全的構(gòu)建器
Kotlin相比Java語(yǔ)言有哪些優(yōu)點(diǎn)?
Kotlin JavaScript反射
Kotlin 是什么?
Kotlin泛型
Kotlin慣用語(yǔ)法
Kotlin與OSGi
Kotlin數(shù)據(jù)類型
Kotlin是面向?qū)ο筮€是函數(shù)式語(yǔ)言?
Kotlin動(dòng)態(tài)類型
Kotlin協(xié)程
Kotlin操作符符重載
Kotlin使用Gradle
Kotlin密封類
Kotlin兼容性
Kotlin集合
Kotlin調(diào)用JavaScript
Kotlin null值安全
Kotlin函數(shù)
Kotlin開發(fā)環(huán)境設(shè)置(IntelliJ IDEA)
Kotlin嵌套類
Kotlin控制流程
Kotlin和Java語(yǔ)言比較
Kotlin 與 Java 語(yǔ)言兼容嗎?
Kotlin教程
Kotlin類和繼承
Kotlin對(duì)象表達(dá)式和對(duì)象聲明
JavaScript中調(diào)用Kotlin
Kotlin區(qū)間/范圍
Kotlin數(shù)據(jù)類
Kotlin lambda表達(dá)式
Kotlin是免費(fèi)的嗎?
Kotlin包
使用Kotlin進(jìn)行Android開發(fā)
在Java中調(diào)用Kotlin代碼
Kotlin this表達(dá)式
使用Kotlin進(jìn)行JavaScript開發(fā)
Kotlin擴(kuò)展
Kotlin解構(gòu)聲明
Kotlin注解
Kotlin使用Maven

Kotlin內(nèi)聯(lián)函數(shù)

內(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ì)象和類)和虛擬調(diào)用會(huì)引入運(yùn)行時(shí)間開銷。

但是在許多情況下通過(guò)內(nèi)聯(lián)化 lambda 表達(dá)式可以消除這類的開銷。
下述函數(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()
}

這個(gè)不是我們從一開始就想要的嗎?

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

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

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

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

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

如果你只想被(作為參數(shù))傳給一個(gè)內(nèi)聯(lián)函數(shù)的 lamda 表達(dá)式中只有一些被內(nèi)聯(lián),你可以用 noinline 修飾符標(biāo)記
一些函數(shù)參數(shù):

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

可以內(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)有
具體化的類型參數(shù),編譯器會(huì)產(chǎn)生一個(gè)警告,因?yàn)閮?nèi)聯(lián)這樣的函數(shù)
很可能并無(wú)益處(如果你確認(rèn)需要內(nèi)聯(lián),則可以關(guān)掉該警告)。

非局部返回

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

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

但是如果 lambda 表達(dá)式傳給的函數(shù)是內(nèi)聯(lián)的,該 return 也可以內(nèi)聯(lián),所以它是允許的:

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

這種返回(位于 lambda 表達(dá)式中,但退出包含它的函數(shù))稱為非局部返回。 我們習(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()
    }
    // ……
}

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

具體化的類型參數(shù)

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

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?
}

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

treeNode.findParentOfType(MyTreeNode::class.java)

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

treeNode.findParentOfType<MyTreeNode>()

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

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

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

inline fun <reified T> membersOf() = T::class.members

fun main(s: Array<String>) {
    println(membersOf<StringBuilder>().joinToString("\n"))
}

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

相關(guān)底層描述,請(qǐng)參見(jiàn)規(guī)范文檔。

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

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

val foo: Foo
    inline get() = Foo()

var bar: Bar
    get() = ……
    inline set(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)。