<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之旅 廣告
                # 擴展 Kotlin 類似于 C# 和 Gosu 提供的在不繼承類或使用如“裝飾模式”一樣的設計模式的情況下利用新功能擴展現有類的功能。通過稱為_擴展_的特殊的聲明。Kotlin 支持_擴展函數_和_擴展屬性_。 ## 擴展函數 要聲明擴展函數,我們需要在前面加上一個接受類型,意即要擴展這個類型。下面的代碼添加一個 `swap` 函數到 `MutableList<Int>`: ``` kotlin fun MutableList<Int>.swap(index1: Int, index2: Int) { val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp } ``` 擴展函數中的 `this` 關鍵字相當于接受者對象(在點號之前傳遞的)。現在,我們可以在任何 `MutableList<Int>` 上調用這個函數: ``` kotlin val l = mutableListOf(1, 2, 3) l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l' ``` 當然,這個函數在任何 `MutableList<T>` 中也講得通,并且我們可以把它做成泛型: ``` kotlin fun <T> MutableList<T>.swap(index1: Int, index2: Int) { val tmp = this[index1] // 'this' corresponds to the list this[index1] = this[index2] this[index2] = tmp } ``` 為了在接收者類型表達式中能獲得泛型,我們在函數名之前我們聲明了泛型類型參數。查看[泛型函數](generics.html) ## 擴展是**靜態地**解析 事實上擴展并沒有更改類。定義一個擴展,你并非在類中插入一個新成員,只不過使用新函數可以在這個類實例上隨點標記被調用。 我們要強調擴展函數是**靜態地**處理,意即它們對于接受類型并不可見。這個意思是擴展函數的調用由要調用的函數表達式類型指明,而不是在運行時通過評估表達式結果的類型。例如: ``` kotlin open class C class D: C() fun C.foo() = "c" fun D.foo() = "d" fun printFoo(c: C) { println(c.foo()) } printFoo(D()) ``` 這個例子將打印“ c ”,因為擴展函數的調用僅僅依賴參數 `c` 的類型,即類 `C`。 如果某個類有一個成員函數,而某個擴展函數又定義了相同的接受類型、相同的名稱而產生了沖突,那么**成員總是勝出**。例如: ``` kotlin class C { fun foo() { println("member") } } fun C.foo() { println("extension") } ``` 如果我們調用 `C` 類型任何 `c` 的 `c.foo()`,那么它將會打印 “member”,而非 “extension”。 ## 可空接受者 注意擴展可以定義為一個可為空的接受類型。這樣擴展可以在一個對象變量上被調用即即使它的值為 null,并可以在內部檢查 `this == null`。這允許你在 Kotlin 中調用 toString() 而不用檢查 null:該檢查在擴展函數內部發生。 ``` kotlin fun Any?.toString(): String { if (this == null) return "null" // after the null check, 'this' is autocast to a non-null type, so the toString() below // resolves to the member function of the Any class return toString() } ``` ## 擴展屬性 類似于函數,Kotlin 支持擴展屬性: ``` kotlin val <T> List<T>.lastIndex: Int get() = size - 1 ``` 注意,由于擴展事實上并非插入成員到類里面,所以沒有高效的方法讓擴展屬性有一個[后臺字段](properties.html#backing-fields)。這就是為什么**擴展屬性不允許有初始器**。它們的行為只能通過明確地提供 getter/setter 來定義。 示例: ``` kotlin val Foo.bar = 1 // error: initializers are not allowed for extension properties ``` ## 伙伴對象擴展 如果某個類定義了[伙伴對象](object-declarations.html#companion-objects),你還可以為這個伙伴對象定義擴展函數和屬性: ``` kotlin class MyClass { companion object { } // will be called "Companion" } fun MyClass.Companion.foo() { // ... } ``` 就像該伙伴對象的普通成員一樣,它們只能使用類名限定符調用: ``` kotlin MyClass.foo() ``` ## 擴展的作用域 大多數時候我們在頂層定義擴展,意即直接在包下面: ``` kotlin package foo.bar fun Baz.goo() { ... } ``` 要在聲明它的包以外使用這種擴展,我們需要在調用地方導入它: ``` kotlin package com.example.usage import foo.bar.goo // importing all extensions by name "goo" // or import foo.bar.* // importing everything from "foo.bar" fun usage(baz: Baz) { baz.goo() ) ``` 更多信息查看 [導入](packages.html#imports)。 ## 聲明擴展為成員 你可以在一個類里為其它類聲明擴展。在這種擴展里有多個_隱含接收者_ —— 可以不用限定符訪問的對象成員。聲明這個擴展的類的實例叫做_發送接受者_,而這個擴展方法的接受類型的實例稱做_擴展接受者_. ``` kotlin class D { fun bar() { ... } } class C { fun baz() { ... } fun D.foo() { bar() // 調用 D.bar baz() // 調用 C.baz } fun caller(d: D) { d.foo() // 調用擴展函數 } } ``` 在發送接受者的成員和擴展接受者的名稱之間發生沖突的情況下,擴展接受者獲得優先權。要關聯到發送接受者的成員,你可以使用[退定 `this` 語法](this-expressions.html#qualified)。 ``` kotlin class C { fun D.foo() { toString() // calls D.toString() this@C.toString() // calls C.toString() } ``` 被聲明為成員的擴展可以聲明為 `open` 并可以被子類覆蓋。這意思是說這種函數的調度會對考慮到發送接受者的類型生效,但會以靜態考慮擴展接受者的類型。 ``` kotlin open class D { } class D1 : D() { } open class C { open fun D.foo() { println("D.foo in C") } open fun D1.foo() { println("D1.foo in C") } fun caller(d: D) { d.foo() // 調用擴展函數 } } class C1 : C() { override fun D.foo() { println("D.foo in C1") } override fun D1.foo() { println("D1.foo in C1") } } C().caller(D()) // 打印 "D.foo in C" C1().caller(D()) // 打印 "D.foo in C1" - 發送接受者被確定為有效 C().caller(D1()) // 打印 "D.foo in C" - 擴展接受者被確定為靜態 ``` ## 動機 在 Java 中,我們會用名為 “\*Utils” 的類:`FileUtils`、`StringUtils`等等。著名的 `java.util.Collections` 亦屬此類。而且這種類最讓人蛋疼的地方就是使用它們的代碼看上去類似這樣: ``` java // Java Collections.swap(list, Collections.binarySearch(list, Collections.max(otherList)), Collections.max(list)) ``` 那些類的名字始終這樣寫。我們可以使用靜態導入: ``` java // Java swap(list, binarySearch(list, max(otherList)), max(list)) ``` 這樣稍微好一點點,但我們無法(或是一點點)從 IDE 的代碼完成中得到幫助。如果我們這樣的話也許會好很多 ``` java // Java list.swap(list.binarySearch(otherList.max()), list.max()) ``` 但我們不可能實現 `List` 類里面所有可能的方法,對嗎?這就是擴展能幫到我們的地方。
                  <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>

                              哎呀哎呀视频在线观看