<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] Kotlin 能夠擴展一個類的新功能而無需繼承該類或者使用像裝飾者這樣的設計模式。這通過叫做**擴展**的特殊聲明完成。 例如,可以從無法修改的第三方庫為類編寫新函數。此類函數可用于以通常方式調用,就像它們是原始類的方法一樣。此機制稱為 [擴展函數]。還有一些 [擴展屬性] 允許您為現有類定義新屬性。 ## 擴展函數 聲明一個擴展函數,我們需要用一個 _接收者類型_ 也就是被擴展的類型來作為他的前綴。下面代碼為 `MutableList<Int>` 添加一個`swap` 函數: ```kotlin fun MutableList<Int>.swap(index1: Int, index2: Int) { val tmp = this[index1] // “this”對應該列表 this[index1] = this[index2] this[index2] = tmp } ``` 這個 *this*關鍵字在擴展函數內部對應到接收者對象(傳過來的在點符號前的對象) 現在,我們對任意 `MutableList<Int>` 調用該函數了: ```kotlin val list = mutableListOf(1, 2, 3) list.swap(0, 2) // “swap()”內部的“this”會保存“list”的值 ``` 當然,這個函數對任何 `MutableList<T>` 起作用,我們可以泛化它: ```kotlin fun <T> MutableList<T>.swap(index1: Int, index2: Int) { val tmp = this[index1] // “this”對應該列表 this[index1] = this[index2] this[index2] = tmp } ``` 為了在接收者類型表達式中使用泛型,我們要在函數名前聲明泛型參數。參見[泛型函數](http://www.kotlincn.net/docs/reference/generics.html)。 ## 擴展是靜態解析的 擴展不能真正的修改他們所擴展的類。通過定義一個擴展,你并沒有在一個類中插入新成員,僅僅是可以通過該類型的變量用點表達式去調用這個新函數。 我們想強調的是擴展函數是靜態分發的,即他們不是根據接收者類型的虛方法。這意味著調用的擴展函數是由函數調用所在的表達式的類型來決定的,而不是由表達式運行時求值結果決定的。例如: ```kotlin fun main() { //sampleStart open class Shape class Rectangle: Shape() fun Shape.getName() = "Shape" fun Rectangle.getName() = "Rectangle" fun printClassName(s: Shape) { println(s.getName()) } printClassName(Rectangle()) //sampleEnd } ``` 這個例子會輸出 "_Shape_",因為調用的擴展函數只取決于參數 `s` 的聲明類型,該類型是 `Shape` 類。 如果一個類定義有一個成員函數與一個擴展函數,而這兩個函數又有相同的接收者類型、相同的名字,并且都適用給定的參數,這種情況**總是取成員函數**。 例如: ```kotlin fun main() { //sampleStart class Example { fun printFunctionType() { println("Class method") } } fun Example.printFunctionType() { println("Extension function") } Example().printFunctionType() //sampleEnd } ``` This code prints "_Class method_". 當然,擴展函數重載同樣名字但不同簽名成員函數也完全可以: ```kotlin fun main() { //sampleStart class Example { fun printFunctionType() { println("Class method") } } fun Example.printFunctionType(i: Int) { println("Extension function") } Example().printFunctionType(1) //sampleEnd } ``` ## 可空接收者 注意可以為可空的接收者類型定義擴展。這樣的擴展可以在對象變量上調用,即使其值為 null,并且可以在函數體內檢測 `this == null`,這能讓你在沒有檢測 null 的時候調用 Kotlin 中的toString():檢測發生在擴展函數的內部。 ```kotlin fun Any?.toString(): String { if (this == null) return "null" // 空檢測之后,“this”會自動轉換為非空類型,所以下面的 toString() // 解析為 Any 類的成員函數 return toString() } ``` ## 擴展屬性 與函數類似,Kotlin 支持擴展屬性: ```kotlin val <T> List<T>.lastIndex: Int get() = size - 1 ``` 注意:由于擴展沒有實際的將成員插入類中,因此對擴展屬性來說[幕后字段](http://www.kotlincn.net/docs/reference/properties.html#%E5%B9%95%E5%90%8E%E5%AD%97%E6%AE%B5)是無效的。這就是為什么**擴展屬性不能有初始化器**。他們的行為只能由顯式提供的 getters/setters 定義。 例如: ```kotlin val House.number = 1 // 錯誤:擴展屬性不能有初始化器 ``` ## 伴生對象的擴展 如果一個類定義有一個[伴生對象](http://www.kotlincn.net/docs/reference/object-declarations.html#%E4%BC%B4%E7%94%9F%E5%AF%B9%E8%B1%A1) ,你也可以為伴生對象定義擴展函數與屬性。Just like regular members of the companion object,they can be called using only the class name as the qualifier: ```kotlin class MyClass { companion object { } // 將被稱為 "Companion" } fun MyClass.Companion.printCompanion() { println("companion") } fun main() { MyClass.printCompanion() } ``` ## 擴展的作用域 大多數時候我們在頂層定義擴展——直接在包里: ```kotlin package org.example.declarations fun List<String>.getLongestString() { /*……*/} ``` 要使用所定義包之外的一個擴展,我們需要在調用方導入它: ```kotlin package org.example.usage import org.example.declarations.getLongestString fun main() { val list = listOf("red", "green", "blue") list.getLongestString() } ``` 更多信息參見[導入](http://www.kotlincn.net/docs/reference/packages.html#%E5%AF%BC%E5%85%A5) ## 擴展聲明為成員 在一個類內部你可以為另一個類聲明擴展。在這樣的擴展內部,有多個 _隱式接收者_ ——其中的對象成員可以無需通過限定符訪問。擴展聲明所在的類的實例稱為_分發接收者_,擴展方法調用所在的接收者類型的實例稱為 _擴展接收者_ 。 ```kotlin class Host(val hostname: String) { fun printHostname() { print(hostname) } } class Connection(val host: Host, val port: Int) { fun printPort() { print(port) } fun Host.printConnectionString(p: Int) { printHostname() // calls Host.printHostname() print(":") printPort() // calls Connection.printPort() } fun connect() { /*……*/ host.printConnectionString(port) // calls the extension function } } fun main() { Connection(Host("kotl.in"), 443).connect() //Host("kotl.in").printConnectionString(443) // error, the extension function is unavailable outside Connection } ``` 對于分發接收者與擴展接收者的成員名字沖突的情況,擴展接收者優先。要引用分發接收者的成員你可以使用 [限定的 `this` 語法](http://www.kotlincn.net/docs/reference/this-expressions.html#%E9%99%90%E5%AE%9A%E7%9A%84-this)。 ```kotlin class Connection { fun Host.getConnectionString() { toString() // 調用 Host.toString() this@Connection.toString() // 調用 Connection.toString() } } ``` 聲明為成員的擴展可以聲明為 `open` 并在子類中覆蓋。這意味著這些函數的分發對于分發接收者類型是虛擬的,但對于擴展接收者類型是靜態的。 ```kotlin open class Base { } class Derived : Base() { } open class BaseCaller { open fun Base.printFunctionInfo() { println("Base extension function in BaseCaller") } open fun Derived.printFunctionInfo() { println("Derived extension function in BaseCaller") } fun call(b: Base) { b.printFunctionInfo() // 調用擴展函數 } } class DerivedCaller: BaseCaller() { override fun Base.printFunctionInfo() { println("Base extension function in DerivedCaller") } override fun Derived.printFunctionInfo() { println("Derived extension function in DerivedCaller") } } fun main() { BaseCaller().call(Base()) // "Base extension function in BaseCaller" DerivedCaller().call(Base()) // "Base extension function in DerivedCaller" - dispatch receiver is resolved virtually DerivedCaller().call(Derived()) // "Base extension function in DerivedCaller" - extension receiver is resolved statically } ``` ## 關于可見性的說明 擴展的可見性與相同作用域內聲明的[其他實體的可見性](http://www.kotlincn.net/docs/reference/visibility-modifiers.html)相同。例如: * 在文件頂層聲明的擴展可以訪問同一文件中的其他 `private` 頂層聲明; * 如果擴展是在其接收者類型外部聲明的,那么該擴展不能訪問接收者的 `private` 成員。
                  <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>

                              哎呀哎呀视频在线观看