<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、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                上一章總結了模式在 Scala 中的幾種用法,最后提到了匿名函數。這一章,我們具體的去學習如何在匿名函數中使用模式。 如果你參與過 Coursera 上的 [那門 Scala 課程](https://www.coursera.org/course/progfun) ,或者寫過 Scala 代碼,那很可能你已經熟悉匿名函數。比如說,將一組歌名轉換成小寫格式,你可能會定義一個匿名函數傳遞給 `map` 方法: ~~~ val songTitles = List("The White Hare", "Childe the Hunter", "Take no Rogues") songTitles.map(t => t.toLowerCase) ~~~ 或者,利用 Scala 的 _占位符語法(placeholder syntax)_ 得到更加簡短的代碼: ~~~ songTitles.map(_.toLowerCase) ~~~ 目前為止,一切都很順利。不過,讓我們來看一個稍微有些區別的例子:假設有一個由二元組組成的序列,每個元組包含一個單詞,以及對應的詞頻,我們的目標就是去除詞頻太高或者太低的單詞,只保留中間地帶的。需要寫出這樣一個函數: ~~~ wordsWithoutOutliers(wordFrequencies: Seq[(String, Int)]): Seq[String] ~~~ 一個很直觀的解決方案是使用 `filter` 和 `map` 函數: ~~~ val wordFrequencies = ("habitual", 6) :: ("and", 56) :: ("consuetudinary", 2) :: ("additionally", 27) :: ("homely", 5) :: ("society", 13) :: Nil def wordsWithoutOutliers(wordFrequencies: Seq[(String, Int)]): Seq[String] = wordFrequencies.filter(wf => wf._2 > 3 && wf._2 < 25).map(_._1) wordsWithoutOutliers(wordFrequencies) // List("habitual", "homely", "society") ~~~ 這個解法有幾個問題。首先,訪問元組字段的代碼不好看,如果我們可以直接解構出字段,那代碼可能更加美觀和可讀。 幸好,Scala 提供了另外一種寫匿名函數的方式:_模式匹配形式的匿名函數_,它是由一系列模式匹配樣例組成的,正如模式匹配表達式那樣,不過沒有 `match` 。下面是重寫后的代碼: ~~~ def wordsWithoutOutliers(wordFrequencies: Seq[(String, Int)]): Seq[String] = wordFrequencies.filter { case (_, f) `> f > 3 && f < 25 } map { case (w, _) `> w } ~~~ 在兩個匿名函數里,我們只使用了一個匹配案例,因為我們知道這個樣例總是會匹配成功,要解構的數據類型在編譯期就確定了,沒有會出錯的可能。這是模式匹配型匿名函數的一個非常常見的用法。 如果把這些匿名函數賦給其他值,你也會看到它們有著正確的類型: ~~~ val predicate: (String, Int) `> Boolean ` { case (_, f) => f > 3 && f < 25 } val transformFn: (String, Int) `> String ` { case (w, _) => w } ~~~ > 不過要注意,必須顯示的聲明值的類型,因為 Scala 編譯器無法從匿名函數中推導出其類型。 當然,也可以定義一系列更加復雜的的匹配案例。但是你必須的確保對于每一個可能的輸入,都會有一個樣例能夠匹配成功,不然,運行時會拋出 `MatchError` 。 ### 偏函數 有時候可能會定義一個只處理特定輸入的函數。這樣的一種函數能幫我們解決 `wordsWithoutOutliers` 中的另外一個問題:在 `wordsWithoutOutliers` 中,我們首先過濾給定的序列,然后對剩下的元素進行映射,這種處理方式需要遍歷序列兩次。如果存在一種解法只需要遍歷一次,那不僅可以節省一些 CPU,還會使得代碼更簡潔,更具有可讀性。 Scala 集合的 API 有一個叫做 `collect` 的方法,對于 `Seq[A]` ,它有如下方法簽名: ~~~ def collect[B](pf: PartialFunction[A, B]): Seq[B] ~~~ 這個方法將給定的 _偏函數(partial function)_ 應用到序列的每一個元素上,最后返回一個新的序列 - 偏函數做了 `filter` 和 `map` 要做的事情。 那偏函數到底是什么呢?概括來說,偏函數是一個一元函數,它只在部分輸入上有定義,并且允許使用者去檢查其在一個給定的輸入上是否有定義。為此,特質 `PartialFunction` 提供了一個 `isDefinedAt` 方法。事實上,類型 `PartialFunction[-A, +B]` 擴展了類型 `(A) => B`(一元函數,也可以寫成 `Function1[A, B]` )。模式匹配型的匿名函數的類型就是 `PartialFunction` 。 依據繼承關系,將一個模式匹配型的匿名函數傳遞給接受一元函數的方法(如:`map`、`filter`)是沒有問題的,只要這個匿名函數對于所有可能的輸入都有定義。 不過 `collect` 方法接受的函數只能是 `PartialFunction[A, B]` 類型的。對于序列中的每一個元素,首先檢查偏函數在其上面是否有定義,如果沒有定義,那這個元素就直接被忽略掉,否則,就將偏函數應用到這個元素上,返回的結果加入結果集。 現在,我們來重構 `wordsWithoutOutliers` ,首先定義需要的偏函數: ~~~ val pf: PartialFunction[(String, Int), String] = { case (word, freq) if freq > 3 && freq < 25 => word } ~~~ 我們為這個案例加入了 _守衛語句_,不在區間里的元素就沒有定義。 除了使用上面的這種方式,還可以顯示的擴展 `PartialFunction` 特質: ~~~ val pf = new PartialFunction[(String, Int), String] { def apply(wordFrequency: (String, Int)) = wordFrequency match { case (word, freq) if freq > 3 && freq < 25 => word } def isDefinedAt(wordFrequency: (String, Int)) = wordFrequency match { case (word, freq) if freq > 3 && freq < 25 => true case _ => false } } ~~~ 當然,前一種方法更為更為簡潔。 把定義好的 `pf` 傳遞給 `map` 函數,能夠通過編譯期,但運行時會拋出 `MatchError` ,因為我們的偏函數并不是在所有輸入值上都有定義: ~~~ wordFrequencies.map(pf) // will throw a MatchError ~~~ 不過,把它傳遞給 `collect` 函數就能得到想要的結果: ~~~ wordFrequencies.collect(pf) // List("habitual", "homely", "society") ~~~ 這個結果和我們最初的實現所得到的結果是一樣的,因此我們可以重寫 `wordsWithoutOutliers`: ~~~ def wordsWithoutOutliers(wordFrequencies: Seq[(String, Int)]): Seq[String] = wordFrequencies.collect { case (word, freq) if freq > 3 && freq < 25 => word } ~~~ 偏函數還有其他一些有用的性質,比如說,它們可以被直接串聯起來,實現函數式的[責任鏈模式](http://en.wikipedia.org/wiki/Chain-of-responsibility_pattern)(源自于面向對象程式設計)。 偏函數還是很多 Scala 庫和 API 的重要組成部分。比如:[Akka](http://akka.io) 中,actor 處理信息的方法就是通過偏函數來定義的。因此,理解這一概念是非常重要的。 ### 小結 在這一章中,我們學習了另一種定義匿名函數的方法:一系列的匹配樣例,它用一種非常簡潔的方式讓解構數據成為可能。而且,我們還深入到偏函數這個話題,用一個簡單的例子展示了它的用處。 下一章,我們將深入的學習已經出現過的 `Option` 類型,探索其存在的原因及其使用方式。
                  <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>

                              哎呀哎呀视频在线观看