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

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                課程內容: [TOC=2,2] ## 什么是靜態類型?它們為什么有用? 按Pierce的話講:“類型系統是一個語法方法,它們根據程序計算的值的種類對程序短語進行分類,通過分類結果錯誤行為進行自動檢查。” 類型允許你表示函數的定義域和值域。例如,從數學角度看這個定義: ~~~ f: R -> N ~~~ 它告訴我們函數“f”是從實數集到自然數集的映射。 抽象地說,這就是?*具體*?類型的準確定義。類型系統給我們提供了一些更強大的方式來表達這些集合。 鑒于這些注釋,編譯器可以?*靜態地*?(在編譯時)驗證程序是?*合理*?的。也就是說,如果值(在運行時)不符合程序規定的約束,編譯將失敗。 一般說來,類型檢查只能保證?*不合理*?的程序不能編譯通過。它不能保證每一個合理的程序都?*可以*?編譯通過。 隨著類型系統表達能力的提高,我們可以生產更可靠的代碼,因為它能夠在我們運行程序之前驗證程序的不變性(當然是發現類型本身的模型bug!)。學術界一直很努力地提高類型系統的表現力,包括值依賴(value-dependent)類型! 需要注意的是,所有的類型信息會在編譯時被刪去,因為它已不再需要。這就是所謂的擦除。 ## Scala中的類型 Scala強大的類型系統擁有非常豐富的表現力。其主要特性有: * **參數化多態性**?粗略地說,就是泛型編程 * **(局部)類型推斷**?粗略地說,就是為什么你不需要這樣寫代碼`val i: Int = 12: Int` * **存在量化**?粗略地說,為一些沒有名稱的類型進行定義 * **視窗**?我們將下周學習這些;粗略地說,就是將一種類型的值“強制轉換”為另一種類型 ## 參數化多態性 多態性是在不影響靜態類型豐富性的前提下,用來(給不同類型的值)編寫通用代碼的。 例如,如果沒有參數化多態性,一個通用的列表數據結構總是看起來像這樣(事實上,它看起來很像使用泛型前的Java): ~~~ scala> 2 :: 1 :: "bar" :: "foo" :: Nil res5: List[Any] = List(2, 1, bar, foo) ~~~ 現在我們無法恢復其中成員的任何類型信息。 ~~~ scala> res5.head res6: Any = 2 ~~~ 所以我們的應用程序將會退化為一系列類型轉換(“asInstanceOf[]”),并且會缺乏類型安全的保障(因為這些都是動態的)。 多態性是通過指定?*類型變量*?實現的。 ~~~ scala> def drop1[A](l: List[A]) = l.tail drop1: [A](l: List[A])List[A] scala> drop1(List(1,2,3)) res1: List[Int] = List(2, 3) ~~~ ### Scala有秩1多態性 粗略地說,這意味著在Scala中,有一些你想表達的類型概念“過于泛化”以至于編譯器無法理解。假設你有一個函數 ~~~ def toList[A](a: A) = List(a) ~~~ 你希望繼續泛型地使用它: ~~~ def foo[A, B](f: A => List[A], b: B) = f(b) ~~~ 這段代碼不能編譯,因為所有的類型變量只有在調用上下文中才被固定。即使你“釘住”了類型`B`: ~~~ def foo[A](f: A => List[A], i: Int) = f(i) ~~~ …你也會得到一個類型不匹配的錯誤。 ## 類型推斷 靜態類型的一個傳統反對意見是,它有大量的語法開銷。Scala通過?*類型推斷*?來緩解這個問題。 在函數式編程語言中,類型推斷的經典方法是?*Hindley Milner算法*,它最早是實現在ML中的。 Scala類型推斷系統的實現稍有不同,但本質類似:推斷約束,并試圖統一類型。 例如,在Scala中你無法這樣做: ~~~ scala> { x => x } <console>:7: error: missing parameter type { x => x } ~~~ 而在OCaml中你可以: ~~~ # fun x -> x;; - : 'a -> 'a = <fun> ~~~ 在Scala中所有類型推斷是?*局部的*?。Scala一次分析一個表達式。例如: ~~~ scala> def id[T](x: T) = x id: [T](x: T)T scala> val x = id(322) x: Int = 322 scala> val x = id("hey") x: java.lang.String = hey scala> val x = id(Array(1,2,3,4)) x: Array[Int] = Array(1, 2, 3, 4) ~~~ 類型信息都保存完好,Scala編譯器為我們進行了類型推斷。請注意我們并不需要明確指定返回類型。 ## 變性 Variance Scala的類型系統必須同時解釋類層次和多態性。類層次結構可以表達子類關系。在混合OO和多態性時,一個核心問題是:如果T’是T一個子類,Container[T’]應該被看做是Container[T]的子類嗎?變性(Variance)注解允許你表達類層次結構和多態類型之間的關系: | | **含義** | **Scala 標記** | | **協變covariant** | C[T’]是 C[T] 的子類 | [+T] | | **逆變contravariant** | C[T] 是 C[T’]的子類 | [-T] | | **不變invariant** | C[T] 和 C[T’]無關 | [T] | 子類型關系的真正含義:對一個給定的類型T,如果T’是其子類型,你能替換它嗎? ~~~ scala> class Covariant[+A] defined class Covariant scala> val cv: Covariant[AnyRef] = new Covariant[String] cv: Covariant[AnyRef] = Covariant@4035acf6 scala> val cv: Covariant[String] = new Covariant[AnyRef] <console>:6: error: type mismatch; found : Covariant[AnyRef] required: Covariant[String] val cv: Covariant[String] = new Covariant[AnyRef] ^ ~~~ ~~~ scala> class Contravariant[-A] defined class Contravariant scala> val cv: Contravariant[String] = new Contravariant[AnyRef] cv: Contravariant[AnyRef] = Contravariant@49fa7ba scala> val fail: Contravariant[AnyRef] = new Contravariant[String] <console>:6: error: type mismatch; found : Contravariant[String] required: Contravariant[AnyRef] val fail: Contravariant[AnyRef] = new Contravariant[String] ^ ~~~ 逆變似乎很奇怪。什么時候才會用到它呢?令人驚訝的是,函數特質的定義就使用了它! ~~~ trait Function1 [-T1, +R] extends AnyRef ~~~ 如果你仔細從替換的角度思考一下,會發現它是非常合理的。讓我們先定義一個簡單的類層次結構: ~~~ scala> class Animal { val sound = "rustle" } defined class Animal scala> class Bird extends Animal { override val sound = "call" } defined class Bird scala> class Chicken extends Bird { override val sound = "cluck" } defined class Chicken ~~~ 假設你需要一個以`Bird`為參數的函數: ~~~ scala> val getTweet: (Bird => String) = // TODO ~~~ 標準動物庫有一個函數滿足了你的需求,但它的參數是`Animal`。在大多數情況下,如果你說“我需要一個___,我有一個___的子類”是可以的。但是,在函數參數這里是逆變的。如果你需要一個接受參數類型`Bird`的函數變量,但卻將這個變量指向了接受參數類型為`Chicken`的函數,那么給它傳入一個`Duck`時就會出錯。然而,如果將該變量指向一個接受參數類型為`Animal`的函數就不會有這種問題: ~~~ scala> val getTweet: (Bird => String) = ((a: Animal) => a.sound ) getTweet: Bird => String = <function1> ~~~ 函數的返回值類型是協變的。如果你需要一個返回`Bird`的函數,但指向的函數返回類型是`Chicken`,這當然是可以的。 ~~~ scala> val hatch: (() => Bird) = (() => new Chicken ) hatch: () => Bird = <function0> ~~~ ## 邊界 Scala允許你通過?*邊界*?來限制多態變量。這些邊界表達了子類型關系。 ~~~ scala> def cacophony[T](things: Seq[T]) = things map (_.sound) <console>:7: error: value sound is not a member of type parameter T def cacophony[T](things: Seq[T]) = things map (_.sound) ^ scala> def biophony[T <: Animal](things: Seq[T]) = things map (_.sound) biophony: [T <: Animal](things: Seq[T])Seq[java.lang.String] scala> biophony(Seq(new Chicken, new Bird)) res5: Seq[java.lang.String] = List(cluck, call) ~~~ 類型下界也是支持的,這讓逆變和巧妙協變的引入得心應手。`List[+T]`是協變的;一個Bird的列表也是Animal的列表。`List`定義一個操作`::(elem T)`返回一個加入了`elem`的新的`List`。新的`List`和原來的列表具有相同的類型: ~~~ scala> val flock = List(new Bird, new Bird) flock: List[Bird] = List(Bird@7e1ec70e, Bird@169ea8d2) scala> new Chicken :: flock res53: List[Bird] = List(Chicken@56fbda05, Bird@7e1ec70e, Bird@169ea8d2) ~~~ `List`?*同樣*?定義了`::[B >: T](x: B)`?來返回一個`List[B]`。請注意`B >: T`,這指明了類型`B`為類型`T`的超類。這個方法讓我們能夠做正確地處理在一個`List[Bird]`前面加一個`Animal`的操作: ~~~ scala> new Animal :: flock res59: List[Animal] = List(Animal@11f8d3a8, Bird@7e1ec70e, Bird@169ea8d2) ~~~ 注意返回類型是`Animal`。 ## 量化 有時候,你并不關心是否能夠命名一個類型變量,例如: ~~~ scala> def count[A](l: List[A]) = l.size count: [A](List[A])Int ~~~ 這時你可以使用“通配符”取而代之: ~~~ scala> def count(l: List[_]) = l.size count: (List[_])Int ~~~ 這相當于是下面代碼的簡寫: ~~~ scala> def count(l: List[T forSome { type T }]) = l.size count: (List[T forSome { type T }])Int ~~~ 注意量化會的結果會變得非常難以理解: ~~~ scala> def drop1(l: List[_]) = l.tail drop1: (List[_])List[Any] ~~~ 突然,我們失去了類型信息!讓我們細化代碼看看發生了什么: ~~~ scala> def drop1(l: List[T forSome { type T }]) = l.tail drop1: (List[T forSome { type T }])List[T forSome { type T }] ~~~ 我們不能使用T因為類型不允許這樣做。 你也可以為通配符類型變量應用邊界: ~~~ scala> def hashcodes(l: Seq[_ <: AnyRef]) = l map (_.hashCode) hashcodes: (Seq[_ <: AnyRef])Seq[Int] scala> hashcodes(Seq(1,2,3)) <console>:7: error: type mismatch; found : Int(1) required: AnyRef Note: primitive types are not implicitly converted to AnyRef. You can safely force boxing by casting x.asInstanceOf[AnyRef]. hashcodes(Seq(1,2,3)) ^ scala> hashcodes(Seq("one", "two", "three")) res1: Seq[Int] = List(110182, 115276, 110339486) ~~~ **參考**?D. R. MacIver寫的[Scala中的存在類型](http://www.drmaciver.com/2008/03/existential-types-in-scala/) Built at?[@twitter](http://twitter.com/twitter)?by?[@stevej](http://twitter.com/stevej),?[@marius](http://twitter.com/marius), and?[@lahosken](http://twitter.com/lahosken)?with much help from?[@evanm](http://twitter.com/evanm),?[@sprsquish](http://twitter.com/sprsquish),?[@kevino](http://twitter.com/kevino),?[@zuercher](http://twitter.com/zuercher),?[@timtrueman](http://twitter.com/timtrueman),?[@wickman](http://twitter.com/wickman), and[@mccv](http://twitter.com/mccv); Russian translation by?[appigram](https://github.com/appigram); Chinese simple translation by?[jasonqu](https://github.com/jasonqu); Korean translation by?[enshahar](https://github.com/enshahar); Licensed under the?[Apache License v2.0](http://www.apache.org/licenses/LICENSE-2.0).
                  <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>

                              哎呀哎呀视频在线观看