<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之旅 廣告
                ## 泛型類型參數 泛型允許你定義帶類型形參的類型。當這種類型的實例被創建出來的時候,類型形參被替換成稱為類型實參的具體類型。 還可以給一個類聲明多個類型形參。例如,Map 類就有鍵類型和值類型這兩個類型形參:`Map<String, Person>`. 和一般類型一樣, Kotlin 編譯器也常常能推導出類型實參: ``` val authors = listOf("Dmitry", "Svetlana") ``` 因為傳給listOf 函數的兩個值都是字符串,編譯器推導出你正在創建一個` List <String >` 。另一方面,如果你想創建一個空的列表,這樣就沒有任何可以推導出類型實參的線索,你就得顯式地指定它(類型形參)。就創建列表來說,既可以選擇在變量聲明中說明泛型的類型,也可以選擇在創建列表的函數中說明類型實參。參看下面的例子: ``` val readers: MutableList<String> = mutableListOf() val readers = mutableListOf<String>() ``` >[info]注意:這兩種聲明是等價的 和Java 不同, Kotlin 始終要求類型實參要么被顯式地說明,要么能被編譯器推導出來。因為泛型是在1.5 版本才引入到Java 的,它必須保證和基于老版本Java 編寫的代碼兼容,所以它九許使用沒有類型參數的泛型類型一一所謂的原生態類型。例如,在Java 中,可以聲明List 類型的變量,而不需要說明它可以包含哪類事物。而Kotlin 從一開始就有泛型,所以它不支持原生態類型,類型實參必須定義。 ### 泛型函數和屬性 如果要編寫一個使用列表的函數,希望它可以在任何列表(通用的列表)上使用,而不是某個具體類型的元素的列表,需要編寫一個泛型函數。泛型函數有它自己的類型形參。這些類型形參在每次函數調用時都必須替換成具體的類型實參。 大部分使用集合的庫函數都是泛型的。來看看圖中的slice 函數。這個函數返回一個只包含在指定下標區間內的元素。 ![](https://img.kancloud.cn/bf/74/bf7442367ce052b70343cfe6dd7201cc_429x238.png) 接收者和返回類型用到了函數的類型形參T , 它們的類型都是List <T>。當你在一個具體的列表上調用這個函數時, 可以顯式地指定類型實參。但是大部分情況下你不必這樣做,因為編譯器會推導出類型,如下所示。 ![](https://img.kancloud.cn/59/56/59562f0115ae65160e117763d2b90a7d_609x143.png) 輸出結果 ``` [a, b, c] [k, l, m, n] ``` 這兩次調用的結果都是`List<Char>`。編譯器把函數返回類型`List<T>`中的T替換成了推導出來的類型Char。 可以給類或接口的方法、頂層函數,以及擴展函數聲明類型參數。在前面的例子中,類型參數用在了接收者和(lambda)參數的類型上,就像上面代碼清單那樣:類型參數T是接收者類型`List<T>` 的一部分,也用在了參數的函數類型`(T) ->Boolean`上。 還可以用同樣的語法聲明泛型的擴展屬性。例如下面這個返回列表倒數第二個元素的擴展屬性: ![](https://img.kancloud.cn/74/49/7449aa3aaa885631bba75269ba404cf3_595x156.png) >[info]**不能聲明泛型非擴展屬性** 普通(即非擴展)屬性不能擁有類型參數,不能在一個類的屬性中存儲多個不同類型的值,因此聲明泛型非擴展函數沒有任何意義。你可以嘗試一下,編譯器會報告錯誤: `>>> val <T> x: T = TODO() ` ERROR: type parameter of a property must be used in its receiver type ### 如何聲明泛型類 和Java 一樣, Kotlin 通過在類名稱后加上一對尖括號,井把類型參數放在尖括號內來聲明泛型類及泛型接口。一旦聲明之后,就可以在類的主體內像其他類型一樣使用類型參數。 ![](https://img.kancloud.cn/b5/b6/b5b6b9d742c7cf381755f5f5a446b2aa_527x142.png) 如果你的類繼承了泛型類(或者實現了泛型接口),你就得為基礎類型的泛型形參提供一個類型實參。它可以是具體類型或者另一個類型形參 ![](https://img.kancloud.cn/e6/c8/e6c8b9e0f0860c41511346804176cac6_735x157.png) StringList 類被聲明成只能包含Str i ng 元素,所以它使用String作為基礎類型的類型實參。子類中的任何函數都要用這個正確的類型換掉T ,所以在StringList 中你會得到函數簽名`get (Int): String` ,而不是`fun get(Int ): T` 。 而類ArrayList 定義了它自己的類型參數T 并把它指定為父類的類型實參。注意`ArrayList<T>`中的T 和`List <T>` 中的T 不一樣,它是全新的類型形參,不必保留一樣的名稱。 一個類甚至可以把它自己作為類型實參引用。實現Comparable 接口的類就是這種模式的經典例子。任何可以比較的元素都必須定義它如何與同樣類型的對象比較: ``` interface Comparable<T> { fun compareTo(other: T): Int } class String : Comparable<String> { override fun compareTo(other: String): Int = /* ... */ } ``` String類實現了Comparable 泛型接口,提供類型String給類型實參T 。 ### 類型參數約束 類型參數約束可以限制作為(泛型)類和(泛型)函數的類型實參的類型。以計算列表元素之和的函數為例。它可以用在`List<Int>`和`List<Double>`上,但不可以用在`List<String>`這樣的列表上。可以定義一個類型參數約束,說明sum 的類型形參必須是數字,來表達這個限制。 現在讓我們編寫一個找出兩個條目中最大值的泛型函數。因為只有在可以相互比較的條目之中才能找出最大值, 需要在函數簽名中說明這一點。做法如下 ![](https://img.kancloud.cn/75/b3/75b3f6dfe2ddd6a922d108b83f9d1d16_731x161.png) 當你試圖對不能比較的條目調用max 方法時,代碼不會編譯: ``` >>> println(max("kotlin", 42)) ERROR: Type parameter bound for `T` is not satisfied: inferred type `Any` is not a subtype of `Comparable<Any>` ``` T 的上界是泛型類型`Comparable<T>`。前面己經看到了, String類繼承了`Comparable<String>`,這樣使得String變成了max 函數的有效類型實參。 極少數情況下,需要在一個類型參數上指定多個約束,這時你需要使用稍微不同的語法。例如下面這個代碼清單用泛型的方式保證給定的`CharSequence` 以句號結尾。標準`StringBuilder` 類和`java.nio.CharBuffer` 類都適用。 ![](https://img.kancloud.cn/e5/62/e562f02a60adcf00c227ad7f473d912c_660x300.png) 這種情況下,可以說明作為類型實參的類型必須實現CharSequence和 Appendable兩個接口。這意味著該類型的值可以使用訪問數據( endsWith )和修改數據( append )兩種操作。 ### 讓類型形參非空 如果你聲明的是泛型類或者泛型函數,任何類型實參,包括那些可空的類型實參,都可以替換它的類型形參。事實上,沒有指定上界的類型形參將會使用Any?這個默認的上界 ![](https://img.kancloud.cn/ef/ad/efad0027adb54fafc2d7f77eee7b4ad9_251x203.png) process 函數中,參數value 是可空的,盡管T 并沒有使用問號標記。 如果你想保證替換類型形參的始終是非空類型,可以通過指定一個約束來實現。如果你除了可空性之外沒有任何限制,可以使用Any 代替默認的`Any?`作為上界: ![](https://img.kancloud.cn/94/16/94168b4971c9ae4219b78698bfc0e2f1_504x157.png) 約束`<T:Any>`確保了類型T 永遠都是非空類型。編譯器不會接收代碼`Processor<String?>` , 因為類型實參`String?`不是Any 的子類型(它是Any?的子類型,一種更普通的類型) : ``` >>> val nullableStringProcessor = Processor<String?>() Error: Type argument is not within its bounds: should be subtype of 'Any' ``` >[info]注意,可以通過指定任意非空類型作為上界,來讓類型參數非空,不光是類型Any 。
                  <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>

                              哎呀哎呀视频在线观看