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

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### 1. 泛型類 > **個人理解:**泛型實質就是類或方法在定義時沒有給定具體參數類型,需要在編譯或運行時自動推斷出類型的一種方法。 - 用方括號來定義類型參數,放在類名后面。下面就定義了一個帶有兩個類型參數T和S的類。 ~~~ class Pair[T, S](val first: T, val second: S) { override def toString = "(" + first + "," + second + ")" } ~~~ - 在類的定義中,可以用類型參數類定義變量、方法參數,以及返回值類型。 - 帶有一個或多個類型參數的類是泛型的,Scala會從構造參數推斷出實際類型,也可以自己指定類型。 ~~~ val p = new Pair(42, "String") val p2 = new Pair[Any, Any](42, "String") ~~~ ### 2. 泛型函數 - 函數和方法也可以帶類型參數,類型參數放在函數名或方法名后面。 ~~~ def getMiddle[T](a: Array[T]) = a(a.length / 2) ~~~ ### 3. 類型變量界定 > **個人理解:**使用類型參數定義了某個參數或變量之后,要使用某種類型的的方法,比如使用String類型的compareTo方法,但我們可能傳進去的是一個Int類型,Int類型沒有該方法,這時程序就會出錯,下面就介紹如何解決這類問題。 - 有時需要對類型變量進行限制,比如有個Pair類,該類中使用了compareTo方法,但我們并不知道first有這個方法。 ~~~ class Pair[T](val first: T, val second: T) { def smaller = if (first.compareTo(second) < 0) first else second // Error } ~~~ - 解決方法,添加一個上界`T <: Comparable[T]`。 ~~~ // 這里要求T必須是Comparable[T]的子類型。 class Pair[T <: Comparable[T]](val first: T, val second: T) { def smaller = if (first.compareTo(second) < 0) first else second } ~~~ - 如果我們現在想要定義一個方法,用一個值替換上面定義Pair中的第一個值,如果Pair是不可變的,我們就需要返回新的Pair。這時候我們要引入**下界**來解決這個問題,下界用`[R >: T]`來表示。 ~~~ // 替換進來的類型必須是原類型的超類型 // 比如現在有Pair[Student],要用Person來替換第一個值,結果是Pair[Person]。 class Pair[T](val first: T, val second: T) { def replaceFirst[R >: T](newFirst: R) = new Pair(newFirst, second) } ~~~ ### 4. 視圖界定 > **個人理解:**即使上面使用上界約束了傳入的類型,我們在調用`Pair(1,4)`時,編譯器還是會報Int不是Comparable[Int]子類的錯誤,其實我們有一個RichInt中實現了該方法,Int到RichInt可以通過隱式轉換來完成。下面就是講解如何用視圖界定的方法解決該問題。 - 視圖界定中使用`<%`關系表示T可以被隱式轉換成Comparable[T]。 ~~~ class Pair[T <% Comparable[T]](val first: T, val second: T) { def smaller = if (first.compareTo(second) < 0) first else second } // Ordered提供關系操作符 class Pair[T <% Ordered[T]](val first: T, val second: T) { def smaller = if (first < second) first else second } ~~~ - 隱式轉換將在后面一個Chapter中講解,這里只要知道有這個概念就行。 ### 5. 上下文界定 > **個人理解:**其實上面視圖界定還有一個問題,當你使用視圖界定前必須知道有從T到V的隱式轉換存在,要是沒有呢,我們該怎么辦?下面就介紹該小結內容”上下文界定“,它是如何解決次問題的。 - 上下文界定的形式是:`T:M`,M是另一個泛型類,它要求必須存在一個類型為M[T]的隱式值,這里只要知道隱式值是用`implicit`定義就可以了,下節會詳細講解。 ~~~ class Pair[T : Ordering](val first: T, val second: T) { def smaller(implicit ord: Ordering[T]) = if (ord.compare(first, second) < 0) first else second } ~~~ ### 6. Manifest上下文界定 > **個人理解:**構造一個泛型數組,在Scala中需要我們將上下文界定的M指定為Manifest,這節其實是上下文界定的一個實際應用場景。 - 要實例化一個泛型的Array[T]或者說是構造一個泛型數組,我們需要一個`Manifest[T]`對象。Manifest就是一個隱式參數,這里可以用上下文界定。 ~~~ def makePair[T : Manifest](first: T, second: T) = { val r = new Array[T](2); r(0) = first; r(1) = second; r } ~~~ ### 7. 多重界定 - 類型變量可以同時有上界和下界:`T >: Lower <: Upper` - 不能同時有多個上界或多個下界,一個類型可以實現多個特質。 ~~~ T <: Comparable[T] with Serializable with Cloneable ~~~ - 可以有多個視圖界定:`T <% Comparable[T] <% String` - 可以有多個上下文界定:`T : Ordering : Manifest` ### 8. 類型約束 > **個人理解:**該小節提出類型約束,主要是要掌握它的兩種用途。 - 類型約束有如下三種方式: ~~~ T =:= U // 測試T是否等于U T <:< U // 測試T是否是U的子類 T <%< U // 測試T是否被隱式轉換為U ~~~ - 使用約束,需要添加隱式類型證明參數。 ~~~ class Pair[T](val first: T, val second: T)(implicit ev: T <:< Comparable[T]) = // 使用約束 ~~~ - 上面的類型約束的使用并沒有比類型界定帶來更多優點,類型約束主要用在以下兩種場景。 - 類型約束讓你可以在泛型類中定義只能在特定條件下使用的方法。 ~~~ // 即使File不是帶先后順序的,這里還是可以構造出Pair[File] // 只是當你調用smaller方法時,才會報錯 class Pair[T](val first: T, val second: T) { def smaller(implicit ev: T <:< Ordered[T]) = // 使用約束 if (first < second) first else second } ~~~ - 類型約束的另一個用途是改進類型推斷。 ~~~ // 下面調用第二條語句會得到推斷的類型參數是[Nothing, List[Int]]不符合[A, C <: Iterable[A]] // 因為單憑List(1, 2, 3)是無法推斷出A是什么,因為它們是在同一個步驟中匹配A和C的。 def firstLast[A, C <: Iterable[A]](it: C) = (it.head, it.last) firstLast(List(1, 2, 3)) // 出錯 ~~~ - 解決辦法是,先匹配C,在匹配A。 ~~~ def firstLast[A, C](it: C)(implicit ev: C <:< Iterable[A]) = (it.head, it.last) firstLast(List(1, 2, 3)) // 成功 ~~~ ### 9. 型變 > **個人理解:**如果只是看書本,這小結還是挺不容易看明白的。其實,仔細分析下,協變和逆變還是很好理解的。如果將父類作為函數參數,想子類作為參數也可以調用,這就是協變;如果將子類作為函數參數,想父類作為參數也可以調用,這就是逆變。這段話如果沒看明白,先看下面具體例子,看完后再回來看這段話。 - 假設有函數定義`def makeFriends(p: Pair[Person])`,并且Student是Person的子類,如果使用Pair[Student]作為參數去調用makeFriends函數,程序會報錯。要想實現這種方式的調用,需要把Pair定義修改如下: ~~~ class Pair[+T](val first: T, val second: T) ~~~ - `+T`(協變)表示某個泛型類的子類型關系和參數T方向一致。 - 下面講解第二種型變方式逆變。 ~~~ trait Friend[-T] { // -T表示逆變 def befriend(someone: T) } class Person(name: String) extends Friend[Person] { def befriend(someone: Person) { this + " and " + someone + " are now friends." } } // Student是Person子類 class Student(name: String) extends Person(name) // 需要注意該函數定義的傳入參數是子類類型 def makeFriendWith(s: Student, f: Friend[Student]) { f.befriend(s) } val susan = new Student("Susan") val fred = new Person("Fred") // 可以調用 makeFriendWith(susan, fred) ~~~ - `-T`(逆變)表示某個泛型類的父類型關系和參數T方向一致,剛好與協變相反。 ### 10. 協變和逆變點 - 函數在參數上是逆變的,返回值上是協變的。逆變適應于表示輸入類型參數,協變適應于表示輸出類型參數。 - Scala中數組類型是不支持型變的,因為它作為輸入和輸出類型要保持不變。 - 參數的位置是逆變點,返回值類型的位置是協變點,在函數的參數中,型變是反過來的,它的參數是協變的。 ~~~ foldLeft[B](z: B)(op: (B, A) => B): B - + + - + ~~~ ### 11. 對象不能泛型 - 不能將參數化類型添加到對象。 ~~~ abstract class List[+T] { def isEmpty: Boolean def head: T def tail: List[T] } // 對象不能寫成 object Empty[T] extends List[T] // 類可以使用 class Empty[T] extends List[T] // 這里可以使用Nothing,前面說過Nothing是所有類型的子類型。 object Empty extends List[Nothing] { def isEmpty = true def head = throw new UnsupportedOperationException def tail = throw new UnsupportedOperationException } ~~~ ### 12. 類型通配符 - Scala中類型可以使用通配符。 ~~~ def process(people: java.util.List[_ <: Person] ~~~ 【待續】
                  <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>

                              哎呀哎呀视频在线观看