<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 內聯函數 [TOC] 使用[高階函數](http://www.kotlincn.net/docs/reference/lambdas.html)會帶來一些運行時的效率損失:**每一個函數都是一個對象,并且會捕獲一個閉包。即那些在函數體內會訪問到的變量。內存分配(對于函數對象和類)和虛擬調用會引入運行時間開銷**。 但是在許多情況下通過內聯化 lambda 表達式可以消除這類的開銷。下述函數是這種情況的很好的例子。即 `lock()` 函數可以很容易地在調用處內聯。 考慮下面的情況: ```kotlin lock(l) { foo() } ``` 編譯器沒有為參數創建一個函數對象并生成一個調用。取而代之,編譯器可以生成以下代碼: ```kotlin l.lock() try { foo() } finally { l.unlock() } ``` 這個不是我們從一開始就想要的嗎?為了讓編譯器這么做,我們需要使用 `inline` 修飾符標記 `lock()` 函數: ```kotlin inline fun <T> lock(lock: Lock, body: () -> T): T { …… } ``` `inline` 修飾符影響函數本身和傳給它的 lambda 表達式:所有這些都將內聯到調用處。 內聯可能導致生成的代碼增加;不過如果我們使用得當(即避免內聯過大函數),性能上會有所提升,尤其是在循環中的“超多態(megamorphic)”調用處。 ## 禁用內聯 **如果希望只內聯一部分傳給內聯函數的 lambda 表達式參數,那么可以用 `noinline` 修飾符標記不希望內聯的函數參數**: ```kotlin inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { …… } ``` 可以內聯的 lambda 表達式只能在內聯函數內部調用或者作為可內聯的參數傳遞,但是 **`noinline` 的可以以任何我們喜歡的方式操作:存儲在字段中、傳送它等等**。 >[success]需要注意的是,如果一個內聯函數沒有可內聯的函數參數并且沒有[具體化的類型參數](http://www.kotlincn.net/docs/reference/inline-functions.html#%E5%85%B7%E4%BD%93%E5%8C%96%E7%9A%84%E7%B1%BB%E5%9E%8B%E5%8F%82%E6%95%B0),編譯器會產生一個警告,因為內聯這樣的函數很可能并無益處(如果你確認需要內聯,則可以用`@Suppress("NOTHING_TO_INLINE")` 注解關掉該警告)。 ## 非局部返回 一般在 Kotlin 中,我們可以只使用一個正常的、非限定的 `return` 來退出一個命名或匿名函數。 這意味著要退出一個 lambda 表達式,我們必須使用一個[標簽](http://www.kotlincn.net/docs/reference/returns.html#%E6%A0%87%E7%AD%BE%E5%A4%84%E8%BF%94%E5%9B%9E),并且在 lambda 表達式內部禁止使用裸 `return`,因為 lambda 表達式不能使包含它的函數返回: ```kotlin fun ordinaryFunction(block: () -> Unit) { println("hi!") } fun foo() { ordinaryFunction { return // 錯誤:不能使 `foo` 在此處返回 } } fun main() { foo() } ``` 運行結果 ``` 'return' is not allowed here ``` 但是**如果 lambda 表達式傳給的函數是內聯的,該 return 也可以內聯,所以它是允許的**: ```kotlin fun foo() { inlined { return // OK:該 lambda 表達式是內聯的 } } fun main() { foo() } ``` 運行結果 ``` hi! ``` 這種返回(位于 lambda 表達式中,但退出包含它的函數)稱為**非局部返回**。 我們習慣了在循環中用這種結構,其內聯函數通常包含: ```kotlin fun hasZeros(ints: List<Int>): Boolean { ints.forEach { if (it == 0) return true // 從 hasZeros 返回 } return false } ``` 請注意,一些內聯函數可能調用傳給它們的不是直接來自函數體、而是來自另一個執行上下文的 lambda 表達式參數,例如來自局部對象或嵌套函數。**在這種情況下,該 lambda 表達式中也不允許非局部控制流**。為了標識這種情況,該 lambda 表達式參數需要用 `crossinline` 修飾符標記: ```kotlin inline fun f(crossinline body: () -> Unit) { val f = object: Runnable { override fun run() = body() } // …… } ``` >[info] `break` 和 `continue` 在**內聯的 lambda 表達式中還不可用**,但我們也計劃支持它們。 ## 具體化的類型參數 有時候我們需要訪問一個作為參數傳給我們的一個類型: ```kotlin 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? } ``` 在這里我們向上遍歷一棵樹并且檢測每個節點是不是特定的類型。這都沒有問題,但是調用處不是很優雅: ```kotlin treeNode.findParentOfType(MyTreeNode::class.java) ``` 我們真正想要的只是傳一個類型給該函數,即像這樣調用它: ```kotlin treeNode.findParentOfType<MyTreeNode>() ``` 為能夠這么做,**內聯函數支持具體化的類型參數**,于是我們可以這樣寫: ```kotlin inline fun <reified T> TreeNode.findParentOfType(): T? { var p = parent while (p != null && p !is T) { p = p.parent } return p as T? } ``` 我們使用 `reified` 修飾符來限定類型參數T,現在可以在函數內部訪問它了,幾乎就像是一個普通的類一樣。由于函數是內聯的,不需要反射,正常的操作符如 `!is`和 `as` 現在都能用了。此外,我們還可以按照上面提到的方式調用它:`myTree.findParentOfType<MyTreeNodeType>()`。 雖然在許多情況下可能不需要反射,但我們仍然可以對一個具體化的類型參數使用它: ```kotlin inline fun <reified T> membersOf() = T::class.members fun main(s: Array<String>) { println(membersOf<StringBuilder>().joinToString("\n")) } ``` **普通的函數(未標記為內聯函數的一些函數)不能有具體化參數**。 **不具有運行時表示的類型(例如非具體化的類型參數或者類似于`Nothing`的虛構類型)不能用作具體化的類型參數的實參**。 相關底層描述,請參見[規范文檔](https://github.com/JetBrains/kotlin/blob/master/spec-docs/reified-type-parameters.md)。 ## 內聯屬性(自 1.1 起) `inline` 修飾符可用于沒有幕后字段的屬性的訪問器get/set函數(方法)。你可以標注獨立的屬性訪問器: ```kotlin val foo: Foo inline get() = Foo() var bar: Bar get() = …… inline set(v) { …… } ``` 你也可以標注整個屬性,將它的兩個訪問器都標記為內聯: ```kotlin inline var bar: Bar get() = …… set(v) { …… } ``` 在調用處,內聯訪問器如同內聯函數一樣內聯。 ## 公有 API 內聯函數的限制 當一個內聯函數是 `public` 或 `protected` 而不是 `private` 或 `internal` 聲明的一部分時,就會認為它是一個[模塊級](http://www.kotlincn.net/docs/reference/visibility-modifiers.html#%E6%A8%A1%E5%9D%97)的公有 API。**可以在其他模塊中調用它,并且也可以在調用處內聯這樣的調用**。 這帶來了一些由模塊做這樣變更時導致的二進制兼容的風險——聲明一個內聯函數但調用它的模塊在它修改后并沒有重新編譯。 為了消除這種由**非公有 API**變更引入的不兼容的風險,**公有 API 內聯函數體內不允許使用非公有聲明**,即,不允許使用 `private` 與 `internal` 聲明以及其部件。 **一個 `internal` 聲明可以由 `@PublishedApi` 標注,這會允許它在公有 API 內聯函數中使用。當一個 `internal` 內聯函數標記有 `@PublishedApi` 時,也會像公有函數一樣檢測其函數體**。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看