<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之旅 廣告
                面向值(value-oriented )編程有很多優勢,特別是用在與函數式編程結構相結合。這種風格強調值的轉換(譯注:由一個不變的值生成另一個不變的值)而非狀態的改變,生成的代碼是指稱透明的(referentially transparent),提供了更強的不變型(invariants),因此容易實現。Case類(也被翻譯為樣本類),模式匹配,解構綁定(destructuring bindings),類型推斷,輕量級的閉包和方法創建語法都是這一類的工具。 ### Case類模擬代數數據類型 Case類可實現代數數據類型(ADT)編碼:它們對大量的數據結構進行建模時有用,用強不變類型(invariants)提供了簡潔的代碼。尤其在結合模式匹配情況下。模式匹配實現了全面解析提供更強大的靜態保護。 (譯注:ADTs是Algebraic Data Type代數數據類型的縮寫,關于這個概念見我的另一篇[博客](http://hongjiang.info/scala-case-class-and-algebraic-data-type/)) 下面是用case類模擬代數數據類型的模式 ~~~ sealed trait Tree[T] case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T] case class Leaf[T](value: T) extends Tree[T] ~~~ 類型 Tree[T] 有兩個構造函器:Node和Leaf。定義類型為sealed(封閉類)允許編譯器進行徹底的分析(這是針對模式匹配的,參考Programming in Scala)因為構造器將不能從外部源文件中添加。 與模式匹配一同,這個建模使得代碼簡潔并且顯然是正確的(obviously correct) ~~~ def findMin[T <: Ordered[T]](tree: Tree[T]) = tree match { case Node(left, right) => Seq(findMin(left), findMin(right)).min case Leaf(value) => value } ~~~ 盡管一些遞歸結構,如樹的組成是典型的ADTs(代數數據類型)應用,它們的用處領域更大。 disjoint,unions特別容易的用ADTs建模;這些頻繁發生在狀態機上(state machines)。 ### Options Option類型是一個容器,空(None)或滿(Some(value))二選一。它提供了使用null的另一種安全選擇,應該盡可能的替代null。它是一個集合(最多只有一個元素)并用集合操所修飾,盡量用Option。 用 ~~~ var username: Option[String] = None ... username = Some("foobar") ~~~ 代替 ~~~ var username: String = null ... username = "foobar" ~~~ 因為前者更安全:Option類型靜態地強制username必須對空(emptyness)做檢測。 對一個Option值做條件判斷應該用foreach ~~~ if (opt.isDefined) operate(opt.get) ~~~ 上面的代碼應該用下面的方式替代: ~~~ opt foreach { value => operate(value)} ~~~ 風格可能看起來有些古怪,但更安全,更簡潔。如果兩種情況都有(Option的None或Some),用模式匹配 ~~~ opt match { case Some(value) => operate(value) case None => defaultAction() } ~~~ 但如果缺少的是缺省值,用getOrElse方法: ~~~ operate(opt getOrElse defaultValue) ~~~ 不要過度使用Option: 如果有一個明確的缺省值——一個[*Null對象*](http://en.wikipedia.org/wiki/Null_Object_pattern)——直接用Null而不必用Option Option還有一個方便的構造器用于包裝空值(nullable value) ~~~ Option(getClass.getResourceAsStream("foo")) ~~~ 得到一個 Option[InputStream] 假定空值(None)時getResourceAsStream會返回null。 ### 模式匹配 模式匹配(x match { …) 在良好的Scala代碼中無處不在:用于合并條件執行、解構(destructuring) 、在構造中造型。使用好模式匹配可以增加程序的明晰度和安全性。 使用模式匹配實現類型轉換: ~~~ obj match { case str: String => ... case addr: SocketAddress => ... ~~~ 模式匹配在和解構(destructuring)聯合使用時效果最好(例如你要匹配case類);下面的寫法 ~~~ animal match { case dog: Dog => "dog (%s)".format(dog.breed) case _ => animal.species } ~~~ 應該被替代為: ~~~ animal match { case Dog(breed) => "dog (%s)".format(breed) case other => other.species } ~~~ 寫[自定義的抽取器](http://www.scala-lang.org/node/112)?(extractor)時必須有雙重構造器(譯注:成對出現的apply方法與unapply方法),否則可能是不適合的。 當默認的方法更有意義時,對條件執行不要用模式匹配。集合庫的方法通常返回Options,避免: ~~~ val x = list match { case head :: _ => head case Nil => default } ~~~ 因為 ~~~ val x = list.headOption getOrElse default ~~~ 更短并且更能表達目的。 ### 偏函數 Scala提供了定義PartialFunction的語法簡寫: ~~~ val pf: PartialFunction[Int, String] = { case i if i%2 == 0 => "even" } ~~~ 它們也可能和 orElse 組合: ~~~ val tf: (Int => String) = pf orElse { case _ => "odd"} tf(1) == "odd" tf(2) == "even" ~~~ 偏函數出現在很多場景,并以PartialFunction有效地編碼 ,例如 方法參數: ~~~ trait Publisher[T] { def subscribe(f: PartialFunction[T, Unit]) } val publisher: Publisher[Int] = .. publisher.subscribe { case i if isPrime(i) => println("found prime", i) case i if i%2 == 0 => count += 2 /* ignore the rest */ } ~~~ 或在返回一個Option的情況下: ~~~ // Attempt to classify the the throwable for logging. type Classifier = Throwable => Option[java.util.logging.Level] ~~~ 可以更好的用PartialFunction表達 ~~~ type Classifier = PartialFunction[Throwable, java.util.Logging.Level] ~~~ 因為它提供了更好的可組合性: ~~~ val classifier1: Classifier val classifier2: Classifier val classifier = classifier1 orElse classifier2 orElse { _ => java.util.Logging.Level.FINEST } ~~~ ### 解構綁定 解構綁定與模式匹配有關。它們用了相同的機制,但解構綁定可應用在當匹配只有一種選項的時候 (以免你接受異常的可能)。解構綁定特別適用于元組(tuple)和樣本類(case class). ~~~ val tuple = ('a', 1) val (char, digit) = tuple val tweet = Tweet("just tweeting", Time.now) val Tweet(text, timestamp) = tweet ~~~ ### 惰性賦值 當使用lazy修飾一個val成員時,其賦值情況是在需要時才賦值的(by need),因為Scala中成員與方法是等價的(除了private[this]成員) ~~~ lazy val field = computation() ~~~ 相當于下面的簡寫: ~~~ var _theField = None def field = if (_theField.isDefined) _theField.get else { _theField = Some(computation()) _theField.get } ~~~ 也就是說,它在需要時計算結果并會記住結果,在要達到這種目的時使用lazy成員;但當語意上需要惰性賦值時(by semantics),要避免使用惰性賦值,這種情況下,最好顯式賦值因為它使得成本模型是明確的,并且副作用被嚴格的控制。 Lazy成員是線程安全的。 ### 傳名調用 方法參數可以指定為傳名參數 (by-name) 意味著參數不是綁定到一個值,而是一個可能需要反復進行的計算。這一特性需要小心使用; 期待傳值(by-value)語法的調用者會感到驚訝。這一特性的動機是構造語法自然的 DSLs——使新的控制結構可以看起來更像本地語言特征。 只在下面的控制結構中使用傳名調用, 調用者明顯傳遞的是一段代碼塊(block)而非一個確定的計算結果。傳名參數必須放在參數列表的最后一位。當使用傳名調用時,確保方法名稱讓調用者明顯感知到方法參數是傳名參數。 當你想要一個值被計算多次,特別是這個計算會引起副作用時,使用顯式函數: ~~~ class SSLConnector(mkEngine: () => SSLEngine) ~~~ 這樣意圖很明確,調用者不會感到驚奇。 ### `flatMap` flatMap——結合了map 和 flatten —— 的使用要特別小心,它有著難以琢磨的威力和強大的實用性。類似它的兄弟 map,它也是經常在非傳統的集合中使用的,例如 Future , Option。它的行為由它的(函數)簽名揭示;對于一些容器 Container[A] ~~~ flatMap[B](f: A => Container[B]): Container[B] ~~~ flatMap對集合中的每個元素調用了 函數 f 產生一個新的集合,將它們全部 flatten 后放入結果中。例如,獲取兩個字符的字符串的所有排列,相同的字符不能出現兩次 ~~~ val chars = 'a' to 'z' val perms = chars flatMap { a => chars flatMap { b => if (a != b) Seq("%c%c".format(a, b)) else Seq() } } ~~~ 等價于下面這段更簡潔的 for-comprehension (基本就是針對上面的語法糖) ~~~ val perms = for { a <- chars b <- chars if a != b } yield "%c%c".format(a, b) ~~~ `flatMap`在處理Options常常很有用—— 它將多個options鏈合并為一個, ~~~ val host: Option[String] = .. val port: Option[Int] = .. val addr: Option[InetSocketAddress] = host flatMap { h => port map { p => new InetSocketAddress(h, p) } } ~~~ 也可以使用更簡潔的for來實現: ~~~ val addr: Option[InetSocketAddress] = for { h <- host p <- port } yield new InetSocketAddress(h, p) ~~~ 對flatMap在在Futures中的使用[futures一節](http://twitter.github.io/effectivescala/index-cn.html#Twitter's%20standard%20libraries-Futures)中有討論。
                  <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>

                              哎呀哎呀视频在线观看