精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

從Java走進Scala:Scala控制結構內部揭密

開發 后端
Scala 是專為 Java平臺編寫的,因此其語法設計會使 Java 代碼編碼人員感覺很輕松。同時,Scala 為 JVM 提供了函數語言的固有的強大功能,并以這些函數設計概念為出發點。在本文中,Ted Neward 將介紹兩種語言之間的細微差異,從一些控制結構(比如 if、while 和 for)開始介紹。正如您將要學習到的那樣,Scala 為這些結構提供了一些在其 Java 等效物中無法獲得的功能和復雜性。

迄今為止,在此系列中,我們已經討論了 Scala 對生態環境的保真度,展示了 Scala 如何將眾多的 Java 核心對象功能合并在一起。如果 Scala 只是編寫對象的另一種方式,那么它不會有任何引人注意的地方,或者說不再那么功能強大。Scala 的函數概念和對象概念的合并,以及它對編程人員效率的重視,這些使得學習 Scala 語言比 Java-cum-Scala 編程人員所想象的體驗更加復雜、更加微妙。

例如,對控制結構(比如 if、while 和 for)使用 Scala 的方法。盡管這些控制結構看起來類似一些老的、還比較不錯的 Java 結構,但實際上 Scala 為它們增加了一些完全不同的特性。本月的文章是關于使用 Scala 控制結構時能夠期望獲得哪些東西的入門級讀物,而不是在制造許多錯誤(并編寫一堆錯誤代碼)之后,讓您冒著遭受挫折的風險去尋找差異。

修訂后的 Person.scala

在 本系列的上一篇文章 中,可以了解到 Scala 能夠通過定義一些方法來定義 POJO,這些方法模仿基于 POJO 的環境所需的傳統 “getter 和 setter”。在這篇文章發表之后,我收到了 Bill Venners 發來的電子郵件,Bill Venners 是即將發表的正式的 Scala 參考資料使用 Scala 編程(請參閱 參考資料)的合著者之一。Bill 指出了實現上述操作的一個更簡單的方法,即使用 scala.reflect.BeanProperty 標注,如下所示:

清單 1. 修改后的 Person.scala 

  1. class Person(fn:String, ln:String, a:Int)  
  2.    {  
  3. @scala.reflect.BeanProperty  
  4. var firstName = fn  
  5.  
  6. @scala.reflect.BeanProperty  
  7. var lastName = ln  
  8.  
  9. @scala.reflect.BeanProperty  
  10. var age = a  
  11.  
  12. override def toString =  
  13.     "[Person firstName:" + firstName + " lastName:" + lastName +  
  14.  " age:" + age + " ]" 
  15.    }  
  16.       

清單 1 中的方法(上一篇文章 中的清單 13 的修訂版)為指定的 var 生成了 get/set 方法對。惟一的缺陷是這些方法并不實際存在于 Scala 代碼中,因此其他 Scala 代碼無法調用它們。這通常不是什么大問題,因為 Scala 將對為自己生成的字段使用已生成的方法;如果事先不知道,那么這些對您而言可能是一個驚喜。

在查看了清單 1 中的代碼之后,最讓我感到震動的是,Scala 并沒有只演示組合函數概念和對象概念的強大威力,它還演示了自 Java ***發布之后的 30 年里對象語言帶來的一些益處。

控制是一種幻想

您將看到的許多奇怪的、不可思議的東西都可以歸功于 Scala 的函數特性,因此,簡單介紹一下函數語言開發和演變的背景可能非常有用。

在函數語言中,將越來越高級的結構直接構建到語言中是不常見的。此外,語言是通過一組核心原語結構定義的。在與將函數作為對象傳遞的功能結合之后,可用來定義功能的高階函數 看起來 像是超出了核心語言的范圍,但實際上它只是一個庫。類似于任何庫,此功能可以替換、擴充或擴展。

根據一組核心原語構建語言的合成 特性由來已久,可以追溯到 20 世紀 60 年代和 70 年代使用 Smalltalk、Lisp 和 Scheme 的時候。諸如 Lisp 和 Scheme 之類的語言因為它們在更低級別的抽象上定義更高級別抽象的能力而受到人們的狂熱追捧。編程人員可以使用高級抽象,用它們構建更高級的抽象。如今聽到討論這個過程時,它通常是關于特定于域的語言(或 DSL)的(請參閱 參考資料)。實際上,它只是關于如何在抽象之上構建抽象的過程。

在 Java 語言中,惟一選擇就是利用 API 調用完成此操作;在 Scala 中,可以通過擴展語言本身實現它。試圖擴展 Java 語言會帶來創建極端場景(corner case)的風險,這些場景將威脅全局的穩定性。而試圖擴展 Scala 則只意味著創建一個新庫。

#p#

If 結構

我們將從傳統的 if 結構開始 —— 當然,此結構必須是最容易處理的結構之一,不是嗎?畢竟,從理論上說,if 只檢查一個條件。如果條件為真,則執行后面跟著的代碼。

但是,這種簡單性可能帶有欺騙性。傳統上,Java 語言對 if 的 else 子句的使用是隨意的,并且假定如果條件出錯,可以只跳過代碼塊。但在函數語句中,情況不是這樣。為了保持函數語句的算術特性,所有一切都必須以表達式計算的方式出現,包括 if 子句本身(對于 Java 開發人員,這正是三元操作符 —— ?: 表達式 —— 的工作方式)。

在 Scala 中,非真代碼塊(代碼塊的 else 部分)必須以與 if 代碼塊中值種類相同的形式呈現,并且必須產生同一種類的值。這意味著不論以何種方式執行代碼,總會產生一個值。例如,請參見以下 Java 代碼:

清單 2. 哪個配置文件?(Java 版)

  1. // This is Java  
  2. String filename = "default.properties";  
  3. if (options.contains("configFile"))  
  4.   filename = (String)options.get("configFile"); 

因為 Scala 中的 if 結構自身就是一個表達式,所以重寫上述代碼會使它們成為清單 3 中所示的更正確的代碼片段:

清單 3. 哪個配置文件?(Scala 版)

  1. // This is Scala  
  2. val filename =  
  3.   if (options.contains("configFile"))  
  4.     options.get("configFile")  
  5.   else 
  6.     "default.properties" 

也就是說,Scala 編程人員通常應該*** val 結構,并在明確需要可變性的時候選擇 var。原因很簡單:除了使編程更容易之外,val 還能確保程序的線程安全性,Scala 中的一個內在主題是:幾乎每次認為需要可變狀態時,其實都不需要可變狀態。讓我們從不可變字段和本地變量(val)開始,這是展示上述情況的一種方法,甚至對最堅定的 Java 懷疑論者也是如此。從 Java 中的 final 開始介紹可能不是很合理,或許是因為 Java 的非函數特性,盡管此原因不可取。一些好奇的 Java 開發人員可能想嘗試一下。
 
盡管真正的贏家是 Scala,但可以通過編寫代碼將結果分配給 val,而不是 var。在設置之后,就無法對 val 進行更改,這與 Java 語言中 final 變量的操作方式是相同的。不可變本地變量最顯著的副作用是很容易實現并發性。試圖用 Java 代碼實現同樣的操作時,會帶來許多不錯的、易讀的好代碼,如清單 4 中所示:

清單 4. 哪個配置文件?(Java 版,三元式)

  1. //This is Java  
  2. final String filename =  
  3.   options.contains("configFile") ?  
  4.     options.get("configFile") : "default.properties"

用代碼評審解釋這一點可能需要點技巧。也許這樣做是正確的,但許多 Java 編程人員會不以為然并且詢問 “您做那個干什么”?

val 與 var

您可能想更多地了解 val 與 var 之間的不同,實際上,它們的不同之處在于 —— 一個是只讀的值,另一個是可變的變量。通常,函數語言,特別是被認為是 “純” 函數語言(不允許帶有副作用,比如可變狀態)的那些函數語言,只支持 val 概念;但是,因為 Scala 要同時吸引函數編程人員和命令/對象編程人員,所以這二種結構它都提供。

已公開的 while 結構

接下來,讓我們來看一下 while 及其同胞 do-while。它們做的基本上是同一件事:測試一個條件,如果該條件為真,則繼續執行提供的代碼塊。

通常,函數語言會避開 while 循環,因為 while 實現的大多數操作都可以使用遞歸來完成。函數語言真地非常類似于 遞歸。例如,可以考慮一下 “Scala by Example”(請參閱 參考資料)中展示的 quicksort 實現,該實現可以與 Scala 實現一起使用:

清單 5. Quicksort(Java 版)

  1. //This is Java  
  2. void sort(int[] xs) {  
  3.   sort(xs, 0, xs.length -1 );  
  4. }  
  5. void sort(int[] xs, int l, int r) {  
  6.   int pivot = xs[(l+r)/2];  
  7.   int a = l; int b = r;  
  8.   while (a <= b)  
  9.     while (xs[a] < pivot) { a = a + 1; }  
  10.     while (xs[b] > pivot) { b = b – 1; }  
  11.     if (a <= b) {  
  12.       swap(xs, a, b);  
  13.       a = a + 1;  
  14.       b = b – 1;  
  15.     }  
  16.   }  
  17.   if (l < b) sort(xs, l, b);  
  18.   if (b < r) sort(xs, a, r);  
  19. }  
  20. void swap(int[] arr, int i, int j) {  
  21.   int t = arr[i]; arr[i] = arr[j]; arr[j] = t;  

不必深入太多的細節,就可以了解 while 循環的用法,它是通過數組中的各種元素進行迭代的,先找到一個支點,然后依次對每個子元素進行排序。毫不令人奇怪的是,while 循環也需要一組可變本地變量,在這里,這些變量被命名為 a 和 b,其中存儲的是當前支點。注意,此版本甚至可以在循環自身中使用遞歸,兩次調用循環本身,一次用于對列表左手邊的內容進行排序,另一次對列表右手邊的內容進行排序。

這足以說明清單 5 中的 quicksort 真的不太容易讀取,更不用說理解它。現在來考慮一下 Scala 中的直接 等同物(這意味著該版本與上述版本盡量接近):

清單 6. Quicksort(Scala 版)

  1. //This is Scala  
  2. def sort(xs: Array[Int]) {  
  3.   def swap(i: Int, j: Int) {  
  4.     val t = xs(i); xs(i) = xs(j); xs(j) = t  
  5.   }  
  6.   def sort1(l: Int, r: Int) {  
  7.     val pivot = xs((l + r) / 2)  
  8.     var i = l; var j = r  
  9.     while (i <= j) {  
  10.       while (xs(i) < pivot) i += 1 
  11.       while (xs(j) > pivot) j -= 1 
  12.       if (i <= j) {  
  13.  swap(i, j)  
  14.  i += 1 
  15.  j -= 1 
  16.       }  
  17.     }  
  18.     if (l < j) sort1(l, j)  
  19.     if (j < r) sort1(i, r)  
  20.   }  
  21.   sort1(0, xs.length 1)  

清單 6 中的代碼看起來非常接近于 Java 版。也就是說,該代碼很長,很難看,并且難以理解(特別是并發性那一部分),明顯不具備 Java 版的一些優點。

所以,我將其改進……

清單 7. Quicksort(更好的 Scala 版)

  1. //This is Scala  
  2. def sort(xs: Array[Int]): Array[Int] =  
  3.   if (xs.length <= 1) xs  
  4.   else {  
  5.     val pivot = xs(xs.length / 2)  
  6.     Array.concat(  
  7.       sort(xs filter (pivot >)),  
  8.            xs filter (pivot ==),  
  9.       sort(xs filter (pivot <)))  
  10.   } 

顯然,清單 7 中的 Scala 代碼更簡單一些。注意遞歸的使用,避免完全 while 循環。可以對 Array 類型使用 filter 函數,從而對其中的每個元素應用 “greater-than”、“equals” 和 “less-than” 函數。事實上,在引導裝入程序之后,因為 if 表達式是返回某個值的表達式,所以從 sort() 返回的是 sort() 的定義中的(單個)表達式。

簡言之,我已經將 while 循環的可變狀態完全再次分解為傳遞給各種 sort() 調用的參數 —— 許多 Scala 狂熱愛好者認為這是編寫 Scala 代碼的正確方式。

可能值得一提的是,Scala 本身并不介意您是否使用 while 代替迭代 —— 您會看到來自編譯器的 “您在干什么,在做蠢事嗎?” 的警告。Scala 也不會阻止您在可變狀態下編寫代碼。但是,使用 while 或可變狀態意味著犧牲 Scala 語言的另一個關鍵方面,即鼓勵編寫具有良好并行性的代碼。只要有可能并且可行,“Scala 式作風” 會建議您優先在命令塊上執行遞歸。

#p#

編寫自己的語言結構

我想走捷徑來討論一下 Scala 的控制結構,做一些大多數 Java 開發人員根本無法相信的事 —— 創建自己的語言結構。

那些通過死讀書學習語言的書呆子會發現一件有趣的事:while 循環(Scala 中的一個原語結構)可能只是一個預定義函數。Scala 文檔以及假設的 “While” 定義中對此進行了解釋說明:

  1. // This is Scala  
  2. def While (p: => Boolean) (s: => Unit) {  
  3.   if (p) { s ; While(p)(s) }  
  4. }  

上述語句指定了一個表達式,該表達式產生了一個布爾值和一個不返回任何結果的代碼塊(Unit),這正是 while 所期望的。

擴展這些代碼行很容易,并且可以根據需要使用它們,只需導入正確的庫即可。正如前面提到的,這是構建語言的綜合方法。在下一節介紹 try 結構的時候,請將這一點牢記于心。

再三嘗試

try 結構允許編寫如下所示代碼:

清單 8. 如果最初沒有獲得成功……

  1. // This is Scala  
  2. val url =  
  3.   try {  
  4.     new URL(possibleURL)  
  5.   }  
  6.   catch {  
  7.     case ex: MalformedURLException =>  
  8.       new URL("www.tedneward.com")  
  9.   } 

清單 8 中的代碼與 清單 2 或 清單 3 中 if 示例中的代碼相差甚遠。實際上,它比使用傳統 Java 代碼編寫更具技巧,特別是在您想捕獲不可變位置上存儲的值的時候(正如我在 清單 4 中最后一個示例中所做的那樣)。這是 Scala 的函數特性的又一個優點!

清單 8 中所示的 case ex: 語法是另一個 Scala 結構(匹配表達式)的一部分,該表達式用于 Scala 中的模式匹配。我們將研究模式匹配,這是函數語言的一個常見特性,稍后將介紹它;現在,只把它看作一個將用于 switch/case 的概念,那么哪種 C 風格的 struct 將用于類呢?

現在,再來考慮一下異常處理。眾所周知,Scala 支持異常處理是因為它是一個表達式,但開發人員想要的是處理異常的標準方法,并不僅僅是捕獲異常的能力。在 AspectJ 中,是通過創建方面(aspect)來實現這一點的,這些方面圍繞代碼部分進行聯系,它們是通過切入點定義的,如果想讓數據庫的不同部分針對不同種類異常采取不同行為,那么必須小心編寫這些切入點 —— SQLExceptions 的處理應該不同于 IOExceptions 的處理,依此類推。

在 Scala 中,這只是微不足道的細節。請留神觀察!

清單 9. 一個自定義異常表達式

  1. // This is Scala  
  2. object Application  
  3. {  
  4.   def generateException()  
  5.   {  
  6.     System.out.println("Generating exception...");  
  7.     throw new Exception("Generated exception");  
  8.   }  
  9.  
  10.   def main(args : Array[String])  
  11.   {  
  12.     tryWithLogging  // This is not part of the language  
  13.     {  
  14.       generateException  
  15.     }  
  16.     System.out.println("Exiting main()");  
  17.   }  
  18.  
  19.   def tryWithLogging (s: => _) {  
  20.     try {  
  21.       s  
  22.     }  
  23.     catch {  
  24.       case ex: Exception =>  
  25.         // where would you like to log this?  
  26.  // I choose the console window, for now  
  27.  ex.printStackTrace()  
  28.     }  
  29.   }  
  30. }  

與前面討論過的 While 結構類似,tryWithLogging 代碼只是來自某個庫的函數調用(在這里,是來自同一個類)。可以在適當的地方使用不同的主題變量,不必編寫復雜的切入點代碼。

此方法的優點在于它利用了 Scala 的捕獲一級結構中橫切邏輯的功能 —— 以前只有面向方面的人才能對此進行聲明。清單 9 中的一級結構捕獲了一些異常(經過檢查的和未經檢查的都包括)并以特定方式進行處理。上述想法的副作用非常多,惟一的限制也許就是想象力了。您只需記得 Scala 像許多函數語言一樣允許使用代碼塊(aka 函數)作為參數并根據需要使用它們即可。

"for" 生成語言

所有這些都引導我們來到了 Scala 控制結構套件的實際動力源泉:for 結構。該結構看起來像是 Java 的增強 for 循環的簡單早期版,但它遠比一般的 Java 編程人員開始設想的更強大。

讓我們來看一下 Scala 如何處理集合上的簡單順序迭代,根據您的 Java 編程經驗,我想您應該非常清楚該怎么做:

清單 10. 對一個對象使用 for 循環和對所有對象使用 for 循環

  1. // This is Scala  
  2. object Application  
  3. {  
  4.   def main(args : Array[String])  
  5.   {  
  6.     for (i <- 1 to 10// the left-arrow means "assignment" in Scala  
  7.       System.out.println("Counting " + i)  
  8.   }  

此代碼所做的正如您期望的那樣,循環 10 次,并且每次都輸出一些值。需要小心的是:表達式 “1 to 10” 并不意味著 Scala 內置了整數感知(awareness of integer)以及從 1 到 10 的計數方式。從技術上說,這里存在一些更微妙的地方:編譯器使用 Int 類型上定義的方法 to 生成一個 Range 對象(Scala 中的任何東西都是對象,還記得嗎?),該對象包含要迭代的元素。如果用 Scala 編譯器可以看見的方式重新編寫上述代碼,那么該代碼看起來很可能如下所示:

清單 11. 編譯器看見的內容

  1. // This is Scala  
  2. object Application  
  3. {  
  4.   def main(args : Array[String])  
  5.   {  
  6.     for (i <- 1.to(10)) // the left-arrow means "assignment" in Scala  
  7.       System.out.println("Counting " + i)  
  8.   }  
  9. }  

實際上,Scala 的 for 并不了解那些成員,并且并不比其他任何對象類型做得更好。它所了解的是 scala.Iterable,scala.Iterable 定義了在集合上進行迭代的基本行為。提供 Iterable 功能(從技術上說,它是 Scala 中的一個特征,但現在將它視為一個接口)的任何東西都可以用作 for 表達式的核心。List、Array,甚至是您自己的自定義類型,都可以在 for 中使用。

#p#

讓 Scala 與英語更接近

您可能已經注意到,理解清單 11 中的 Scala 的 for 循環版本更容易一些。這要感謝 Range 對象暗中將兩端都包含在內,以下英語語言語法比 Java 語言更接近些。假如有一條 Range 語句說 “from 1 to 10, do this”,那么這意味著不再產生意外的 off-by-one 錯誤。

特殊性

正如上面已經證明的那樣,for 循環可以做許多事情,并不只是遍歷可迭代的項列表。事實上,可以使用一個 for 循環在操作過程中過濾許多項,并在每個階段都產生一個新列表:

清單 12. 看一看還有哪些優點

  1. // This is Scala  
  2. object Application  
  3. {  
  4.   def main(args : Array[String])  
  5.   {  
  6.     for (i <- 1 to 10; i % 2 == 0)  
  7.       System.out.println("Counting " + i)  
  8.   }  

注意到清單 12 中 for 表達式的第二個子句了嗎?它是一個過濾器,實際上,只有那些傳遞給過濾器(即計算 true)的元素 “向前傳給” 了循環主體。在這里,只輸出了 1 到 10 的偶數數字。

并不要求 for 表達式的各個階段都成為過濾器。您甚至可以將一些完全平淡無奇的東西(從循環本身的觀點來看)放入管道中。例如以下代碼顯示了在下一個階段進行計算之前的 i 的當前值:

清單 13. 讓我如何愛上您呢?別那么冗長

  1. // This is Scala  
  2. object App  
  3. {  
  4.   def log(item : _) : Boolean =  
  5.   {  
  6.     System.out.println("Evaluating " + item)  
  7.     true 
  8.   }  
  9.  
  10.   def main(args : Array[String]) =  
  11.   {  
  12.     for (val i <- 1 to 10; log(i); (i % 2) == 0)  
  13.       System.out.println("Counting " + i)  
  14.   }  
  15. }  

在運行的時候,范圍 1 到 10 中的每個項都將發送給 log,它將通過顯式計算每個項是否為 true 來 “批準” 每個項。然后,for 的第三個子句將對這些項進行篩選,過濾出那些滿足是偶數的條件的元素。因此,只將偶數傳遞給了循環主體本身。

簡單性

在 Scala 中,可以將 Java 代碼中復雜的一長串語句縮短為一個簡單的表達式。例如,以下是遍歷目錄查找所有 .scala 文件并顯示每個文件名稱的方法:

清單 14. Finding .scala

  1. // This is Scala  
  2. object App  
  3. {  
  4.   def main(args : Array[String]) =  
  5.   {  
  6.     val filesHere = (new java.io.File(".")).listFiles  
  7.     for (  
  8.       file <- filesHere;  
  9.       if file.isFile;  
  10.       if file.getName.endsWith(".scala")  
  11.     ) System.out.println("Found " + file)  
  12.   }  

這種 for 過濾很常見(并且在此上下文中,分號很讓人討厭),使用這種過濾是為了幫助您做出忽略分號的決定。此外,Scala 允許將上述示例中的圓括號之間的語句直接作為代碼塊對待:

清單 15. Finding .scala(版本 2)

  1. // This is Scala  
  2. object App  
  3. {  
  4.   def main(args : Array[String]) =  
  5.   {  
  6.     val filesHere = (new java.io.File(".")).listFiles  
  7.     for {  
  8.       file <- filesHere  
  9.       if file.isFile  
  10.       if file.getName.endsWith(".scala")  
  11.     } System.out.println("Found " + file)  
  12.   }  
  13. }  

作為 Java 開發人員,您可能發現最初的圓括號加分號的語法更直觀一些,沒有分號的曲線括號語法很難讀懂。幸運的是,這兩種句法產生的代碼是等效的。

一些有趣的事

在 for 表達式的子句中可以分配一個以上的項,如清單 16 中所示。

清單 16. 名稱中有什么?

  1. // This is Scala  
  2. object App  
  3. {  
  4.   def main(args : Array[String]) =  
  5.   {  
  6.     // Note the array-initialization syntax; the type (Array[String])  
  7.     // is inferred from the initialized elements  
  8.     val names = Array("Ted Neward""Neal Ford""Scott Davis",  
  9.       "Venkat Subramaniam""David Geary")  
  10.  
  11.     for {  
  12.       name <- names  
  13.       firstName = name.substring(0, name.indexOf(' '))  
  14.     } System.out.println("Found " + firstName)  
  15.   }  
  16. }  

這被稱為 “中途賦值(midstream assignment)”,其工作原理如下:定義了一個新值 firstName,該值用于保存每次執行循環后的 substring 調用的值,以后可以在循環主體中使用此值。

這還引出了嵌套 迭代的概念,所有迭代都位于同一表達式中:

清單 17. Scala grep

  1. // This is Scala  
  2. object App  
  3. {  
  4.   def grep(pattern : String, dir : java.io.File) =  
  5.   {  
  6.     val filesHere = dir.listFiles  
  7.     for (  
  8.       file <- filesHere;  
  9.       if (file.getName.endsWith(".scala") || file.getName.endsWith(".java"));  
  10.       line <- scala.io.Source.fromFile(file).getLines;  
  11.       if line.trim.matches(pattern)  
  12.     ) println(line)  
  13.   }  
  14.  
  15.   def main(args : Array[String]) =  
  16.   {  
  17.     val pattern = ".*object.*" 
  18.       
  19.     grep pattern new java.io.File(".")  
  20.   }  
  21. }  

在此示例中,grep 內部的 for 使用了兩個嵌套迭代,一個在指定目錄(其中每個文件都與 file 連接在一起)中找到的所有文件上進行迭代,另一個迭代在目前正被迭代的文件(與 line 本地變量連接在一起)中發現的所有行上進行迭代。

使用 Scala 的 for 結構可以做更多的事,但目前為止提供的示例已足以表達我的觀點:Scala 的 for 實際上是一條管道,它在將元素傳遞給循環主體之前處理元素組成的集合,每次一個。此管道其中的一部分負責將更多的元素添加到管道中(生成器),一部分負責編輯管道中的元素(過濾器),還有一些負責處理中間的操作(比如記錄)。無論如何,Scala 會帶給您與 Java 5 中引入的 “增強的 for 循環” 不同的體驗。

匹配

今天要了解的最后一個 Scala 控制結構是 match,它提供了許多 Scala 模式匹配功能。幸運的是,模式匹配會聲明對某個值進行計算的代碼塊。首先,將執行代碼塊中最接近的匹配結果。因此,在 Scala 中可以包含以下代碼:

清單 18. 一個簡單的匹配

  1. // This is Scala  
  2. object App  
  3. {  
  4.   def main(args : Array[String]) =  
  5.   {  
  6.     for (arg <- args)  
  7.       arg match {  
  8.  case "Java" => println("Java is nice...")  
  9.  case "Scala" => println("Scala is cool...")  
  10.  case "Ruby" => println("Ruby is for wimps...")  
  11.  case _ => println("What are you, a VB programmer?")  
  12.       }  
  13.   }  

剛開始您可能將 Scala 模式匹配設想為支持 String 的 “開關’,帶有通常用作通配符的下劃線字符,而這正是典型開關中的默認情況。但是,這樣想會極大地低估該語言。模式匹配是許多(但不是大多數)函數語言中可以找到的另一個特性,它提供了一些有用的功能。

對于初學者(盡管這沒什么好奇怪的),可能認為 match 表達式自身會產生一個值,該值可能出現在賦值語句的右邊,正如 if 和 try 語句所做的那樣。這一點本身也很有用,但匹配的真正威力體現在基于各種類型進行匹配時,而不是如上所述匹配單個類型的值,或者更多的時候,它是兩種匹配的組合。

因此,假設您有一個聲明返回 Object 的函數或方法 —— 在這里,Java 的 java.lang.reflect.Method.invoke() 方法的結果可能是一個好例子。通常,在使用 Java 語言計算結果時,首先應該確定其類型;但在 Scala 中,可以使用模式匹配簡化該操作:

清單 19. 您是什么?

  1. //This is Scala  
  2. object App  
  3. {  
  4.   def main(args : Array[String]) =  
  5.   {  
  6.     // The Any type is exactly what it sounds like: a kind of wildcard that  
  7.     // accepts any type  
  8.     def describe(x: Any) = x match {   
  9.       case 5 => "five"   
  10.       case true => "truth"   
  11.       case "hello" => "hi!"   
  12.       case Nil => "the empty list"   
  13.       case _ => "something else"   
  14.     }  
  15.       
  16.     println describe(5)  
  17.     println describe("hello")  
  18.   }  

因為 match 的很容易簡單明了地描述如何針對各種值和類型進行匹配的能力,模式匹配常用于解析器和解釋器中,在那里,解析流中的當前標記是與一系列可能的匹配子句匹配的。然后,將針對另一系列子句應用下一個標記,依此類推(注意,這也是使用函數語言編寫許多語言解析器、編譯器和其他與代碼有關的工具的部分原因,這些函數語言中包括 Haskell 或 ML)。

關于模式匹配,還有許多可說的東西,但這些會將我們直接引導至 Scala 的另一個特性 case 類,我想將它留到下次再介紹。

結束語

Scala 在許多方面看起來都非常類似于 Java,但實際上只有 for 結構存在一些相似性。核心語法元素的函數特性不僅提供了一些有用的特性(比如已經提到的賦值功能),還提供了使用新穎有趣的方式擴展語言的能力,不必修改核心 javac 編譯器本身。這使該語言更加符合 DSL 的定義(這些 DSL 是在現有語言的語法中定義的),并且更加符合編程人員根據一組核心原語(a la Lisp 或 Scheme)構建抽象的愿望。

關于 Scala,有如此多的內容可以談論,但我們這個月的時間已經用完了。記得試用最新的 Scala bits(在撰寫本文時是 2.7.0-final)并嘗試提供的示例,感受一下該語言的操作(請參閱 參考資料)。請記住,到下一次的時候,Scala 會將一些有趣的(函數)特性放入編程中!

【相關閱讀】

  1. Scala編程語言專題
  2. 面向Java開發人員的Scala指南:理解Scala的類語法和語義
  3. 面向Java開發人員的Scala指南:面向對象的函數編程
  4. Scala的類型系統:取代復雜的通配符
  5. Scala的類型系統 比Java更靈活
責任編輯:yangsai 來源: IBMDW
相關推薦

2009-09-28 11:01:39

從Java走進Scal

2009-08-21 16:17:25

ScalaTwitter API

2009-07-15 10:14:25

Scala并發性

2009-12-09 09:15:47

從Java走進ScalTwitter API

2009-02-04 17:32:03

ibmdwJavaScala

2009-06-16 17:54:38

Scala類語法語義

2009-10-14 11:14:38

ScitterScalaTwitter

2009-08-14 11:35:01

Scala Actor

2009-06-17 13:57:25

Scala元組數組

2009-06-16 17:09:17

Scala面向對象函數編程

2009-06-19 10:51:39

Scalapackage訪問修飾符

2009-06-17 13:26:06

scala繼承模型

2009-07-22 07:49:00

Scala控制結構

2009-06-19 11:13:47

Scalacase類模式匹配

2009-06-19 11:42:09

Scala計算器解析

2009-07-08 12:43:59

Scala ServlScala語言

2009-09-09 10:50:55

Scala例子Scala與Java

2009-09-28 10:38:57

Scala教程

2010-09-14 15:34:41

Scala

2009-06-19 13:16:36

Scala計算器解析器組合子
點贊
收藏

51CTO技術棧公眾號

亚洲在线成人精品| 日本成人中文字幕在线视频| 欧美xxxx在线观看| 日本日本19xxxⅹhd乱影响| 少妇一级淫片免费看| 美女精品一区| 久久九九全国免费精品观看| japanese在线观看| jizzjizz少妇亚洲水多| 一区二区三区精密机械公司| 日本亚洲导航| 99在线小视频| 日欧美一区二区| 欧美激情xxxx| 国产伦精品一区二区三区视频女| 欧美一区一区| 欧美在线三级电影| 免费拍拍拍网站| 午夜视频在线| 99re这里只有精品首页| 91天堂在线观看| 手机在线看片1024| 在线播放日韩| 久久久精品国产网站| 欧洲av一区二区三区| 国产精品麻豆| 欧美视频中文字幕| 六月丁香婷婷激情| 不卡av免费观看| 亚洲欧洲精品成人久久奇米网| 久久久久久艹| 国产91免费看| 国产精品1区2区| 国产欧美一区二区三区四区 | 欧美福利视频| 在线观看国产精品日韩av| 男女一区二区三区| 日韩视频1区| 欧美日韩国产精品成人| 亚洲国产精品久久久久婷蜜芽| 97caopor国产在线视频| 国产精品美女久久福利网站| 日本成人三级电影网站| 欧美日韩国产亚洲沙发| 成人精品视频一区二区三区尤物| 亚洲japanese制服美女| 一级全黄少妇性色生活片| 日韩精品欧美成人高清一区二区| 欧美亚洲日本网站| 国产乡下妇女做爰视频| 黄色日韩在线| 久久久久久久久久久91| 久久久久久久久艹| 欧美日韩国产成人精品| 欧美精品免费播放| 青青草免费av| 黑丝一区二区| 国模吧一区二区| 日本在线观看视频网站| 日韩一级不卡| 91精品国产亚洲| www.日本精品| 久久久久.com| 国产精品视频内| 一级特黄aaa大片在线观看| 日本少妇一区二区| 成人av在线网址| 国产女人18毛片18精品| 国产精品综合av一区二区国产馆| 97人人澡人人爽| 国模私拍视频在线| 91一区二区三区在线观看| 久久天天狠狠| 蜜桃免费在线| 国产精品网曝门| 色之综合天天综合色天天棕色| 成人影视在线播放| 国产精品久久久久久福利一牛影视| 一区二区在线高清视频| 91小视频xxxx网站在线| 污片在线观看一区二区| 激情婷婷综合网| 亚洲香蕉久久| 精品国产91乱码一区二区三区 | 伊人夜夜躁av伊人久久| 天堂…中文在线最新版在线| 日本综合字幕| 91麻豆精品国产自产在线| 亚洲一区和二区| 欧美男gay| 久久国产精品久久国产精品| 成年人免费看毛片| 美女视频黄 久久| 97人人模人人爽人人喊38tv| 手机福利小视频在线播放| 日本一区二区三区dvd视频在线| 色撸撸在线观看| 国产黄大片在线观看| 欧亚一区二区三区| 黑森林av导航| 精品一区二区三区中文字幕老牛| 久久福利视频网| 日韩三级视频在线播放| 青青草成人在线观看| eeuss一区二区三区| 麻豆导航在线观看| 亚洲精品国产成人久久av盗摄| 欧美日韩亚洲一| 91成人精品观看| 亚洲美女视频网| 激情小说中文字幕| 免费成人性网站| 麻豆成人在线播放| 污污的网站在线看| 欧美日韩一区二区在线观看视频 | 国产欧美精品一区| 国产va亚洲va在线va| 亚洲精品一区av| 亚洲女同精品视频| 精品无码人妻一区二区三区品 | 五月综合激情| 国产精品pans私拍| 欧美自拍偷拍第一页| 亚洲欧美电影院| 亚洲一二三区av| 欧美天堂影院| 久久久久久久久久久免费 | 日本不卡不码高清免费观看| 国产三区二区一区久久| 国产不卡在线| 欧美三级一区二区| 免费网站在线高清观看| 一本久道久久综合婷婷鲸鱼| 亚洲xxx大片| 在线视频自拍| 欧美在线不卡一区| 国产av自拍一区| 亚洲欧美视频一区二区三区| 国产精品一区二区三区不卡| 色图在线观看| 日韩欧美激情一区| 杨钰莹一级淫片aaaaaa播放| 精品一区二区在线播放| 亚洲精品日韩成人| 视频二区不卡| 国产亚洲精品一区二区| 无码人妻精品一区二区| 久久综合九色综合97_久久久| 99在线精品免费视频| 国产一区在线电影| 欧美福利视频在线观看| 亚洲AV午夜精品| 一个色综合av| 无码人妻丰满熟妇啪啪网站| 亚洲一级电影| 国产伦精品一区二区三区视频免费 | 国产精品毛片视频| 韩国福利视频一区| 天堂av在线免费观看| 色综合久久久久综合99| 97超碰在线资源| 日韩精品成人一区二区三区| 亚洲精品一卡二卡三卡四卡| 亚洲一区二区三区久久久| 欧美富婆性猛交| 四虎在线免费观看| 欧美系列一区二区| 女人裸体性做爰全过| 久久久久国产一区二区| 日韩欧美视频第二区| aa亚洲一区一区三区| 欧美风情在线观看| 国内av一区二区三区| 欧美日韩国产中文| 国产小视频在线看| 久久免费偷拍视频| 欧美国产日韩另类| 一区免费在线| 视频一区视频二区视频三区视频四区国产| 成人在线视频国产| 97国产一区二区精品久久呦| a天堂中文在线88| 欧美一区二区日韩一区二区| 日本视频免费在线| 中文字幕av一区 二区| 久久久久久久久久久久国产精品| 国产精品综合| 国产日韩欧美大片| 久久99影视| av在线不卡一区| av在线不卡精品| 久久久久久亚洲精品中文字幕| 国产在线资源| 欧美成人一区二区三区| 中文字幕在线播| 亚洲一区二区三区国产| 黄免费在线观看| 懂色av一区二区三区免费看| 激情五月亚洲色图| 欧美另类视频| 特级西西444www大精品视频| av自拍一区| 国产精品久久久久久av| 毛片在线网址| 久久精品2019中文字幕| 日本天堂影院在线视频| 91精品国产综合久久香蕉的特点| av黄色在线播放| 最新中文字幕一区二区三区| 亚洲一级中文字幕| 成人h动漫精品一区二区| 日韩精品你懂的| 国产精品夜夜夜| 青青草综合在线| 欧美激情偷拍自拍| 成人在线中文字幕| 亚洲天堂资源| 91精品国产成人| av免费在线免费| 精品国产自在精品国产浪潮| 亚洲人在线观看视频| 日韩免费性生活视频播放| 中文字幕一二区| 福利视频第一区| 国产精品19乱码一区二区三区| 亚洲国产精品激情在线观看 | 鲁大师精品99久久久| 亚洲一区中文字幕在线观看| 久久91超碰青草在哪里看| 5566日本婷婷色中文字幕97| 超碰在线97国产| 久久深夜福利免费观看| 香蕉视频在线免费看| 亚洲成在人线av| 黄色一级a毛片| 欧美xxxx在线观看| 99国产精品99| 日韩一区二区三区电影 | xx欧美视频| 午夜精品一区二区三区在线视| 免费男女羞羞的视频网站在线观看| 91福利资源站| 91麻豆精品在线| 欧美性xxxxx极品少妇| 丁香六月婷婷综合| 色诱亚洲精品久久久久久| 动漫精品一区一码二码三码四码| 亚洲专区一二三| 国产精品久久久免费看| 欧美韩国日本一区| 中文字幕伦理片| 久久精品一区二区三区四区| 亚洲码无人客一区二区三区| 国产日韩欧美不卡在线| 91精品人妻一区二区三区| 国产色产综合产在线视频| 亚洲AV无码国产成人久久| 亚洲国产精品激情在线观看| 特黄一区二区三区| 中文字幕在线不卡一区| 免费三级在线观看| 99九九99九九九视频精品| 亚洲av综合一区二区| 国产欧美精品一区二区三区四区 | 乱码一区二区三区| 成人综合婷婷国产精品久久 | 亚洲第一福利专区| 久久久久无码国产精品一区| 久久不见久久见中文字幕免费| 欧美极品一区二区| 色综合天天爱| 丁香色欲久久久久久综合网| 亚洲性视频h| www.欧美日本| 蜜臀精品久久久久久蜜臀| 日本在线观看视频一区| 国产 欧美在线| a视频免费观看| 国产精品久久久久一区二区三区共| 国产精品久久免费观看| 亚洲欧美区自拍先锋| 久久久久久久黄色片| 91精品福利在线| 精品国产无码AV| 亚洲日韩中文字幕| 欧美激情午夜| 57pao精品| 欧美成人精品一区二区男人小说| 成人午夜黄色影院| 亚洲第一福利社区| 亚洲一区二区三区加勒比 | 乌克兰美女av| 国产精品一级片在线观看| 一级性生活大片| 亚洲欧美自拍偷拍| 狠狠人妻久久久久久| 欧美一区二区精品在线| 亚洲欧美丝袜中文综合| www.亚洲成人| 大黄网站在线观看| 国产欧美在线观看| 免费国产自久久久久三四区久久| 亚洲国产精品日韩| 国产一区二区三区久久| 四虎成人在线播放| 久久伊99综合婷婷久久伊| 青青草在线观看视频| 色婷婷综合激情| 日韩在线视频第一页| 久久最新资源网| 日韩三级影视| 免费在线成人av电影| 狠狠综合久久| 9久久婷婷国产综合精品性色 | 久久机这里只有精品| 野外性满足hd| 亚洲欧美日韩一区| 日韩在线播放中文字幕| 亚洲第一页中文字幕| 免费网站免费进入在线| 国产精品成人一区二区三区吃奶| 奇米影视777在线欧美电影观看| 亚洲乱码一区二区三区| 亚洲欧美视频| 免费在线观看成年人视频| 亚洲黄色小视频| 国产不卡精品视频| 亚洲欧美日本另类| 少妇在线看www| 精品在线视频一区二区| 综合日韩在线| 日本一本在线视频| 亚洲素人一区二区| 中文字幕在线观看视频一区| 国产香蕉一区二区三区在线视频| 三级在线观看视频| 99re在线观看视频| 欧美在线亚洲综合一区| 黑森林福利视频导航| 26uuu精品一区二区| 麻豆精品久久久久久久99蜜桃| 亚洲国产精品成人一区二区| av老司机免费在线| 国产亚洲自拍偷拍| 国内精品久久久久久久影视蜜臀| 日批视频免费看| 亚洲国产一区二区三区| 精品人妻一区二区三区四区不卡 | 欧美日韩综合网| 久久av最新网址| 久久视频精品在线观看| 在线免费观看日本欧美| jizz在线观看视频| 成人精品网站在线观看| 99久久亚洲精品| 亚洲精品手机在线观看| 久久婷婷色综合| 中文字幕 亚洲视频| 久久精品国产欧美亚洲人人爽| 欧美一级在线| 亚洲乱码日产精品bd在线观看| 成人性视频免费网站| 国产亚洲精品成人| 精品一区二区三区电影| 日韩欧美精品一区二区综合视频| 日韩wuma| 国产精品白丝av| 亚洲黄色一区二区| 亚洲精品视频免费| 香蕉成人在线| 亚洲精品一区二区精华| 欧美一区视频在线| 97久久久久久久| xfplay精品久久| 不卡av电影在线| 日韩中文字幕第一页| 欧美天堂在线| 精品人妻大屁股白浆无码| 不卡的看片网站| 草久久免费视频| 中文国产亚洲喷潮| 一区二区三区亚洲变态调教大结局| 中文字幕日韩精品无码内射| 不卡的av在线| www.色国产| 亚洲一区二区久久| 色999久久久精品人人澡69| 久久久天堂国产精品| 99久久精品国产一区二区三区| 亚洲另类在线观看| 色午夜这里只有精品| 国产精品chinese在线观看| 久草综合在线观看| 亚洲人精品一区| 欧美性孕妇孕交| 成人黄视频免费| 久久婷婷av| 久久精品国产亚洲AV无码麻豆| 伊人男人综合视频网| 日韩一区网站|