精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

亚洲第一区在线观看| 国产精品高潮呻吟| 日韩av电影免费观看高清| 日本爱爱爱视频| 欧美日韩中出| 欧美午夜女人视频在线| 亚洲精品一区二区三区樱花 | 日韩天天综合| 国产午夜一区二区| 风韵丰满熟妇啪啪区老熟熟女| 伊人网在线播放| 中文字幕一区二区三区在线观看 | www.xxx亚洲| 中文国产字幕在线观看| 久久精品亚洲麻豆av一区二区 | 国产亚洲欧美色| 99久久综合狠狠综合久久止| 中文字幕一区二区人妻视频| 欧美黄色大片网站| 最近2019中文字幕在线高清 | 99久热这里只有精品视频免费观看| 欧美三级免费观看| 日本福利视频在线观看| 搞黄视频免费在线观看| 99国产精品久久久久久久久久久| 成人国产精品一区| 中文字幕精品视频在线观看| 欧美日韩国产色综合一二三四| 国产一区二区日韩精品欧美精品| 91精品啪在线观看国产| 国产精品高清一区二区| 色av综合在线| 欧美色图色综合| 欧美人与禽猛交乱配| 国产精品传媒入口麻豆| 日韩国产欧美一区| 色视频免费在线观看| 成人毛片在线观看| 亚洲伊人一本大道中文字幕| 在线观看视频二区| 日韩福利视频导航| 日本精品一区二区三区在线| 精品一区二区三区人妻| 中文字幕一区二区三区乱码图片| 中文字幕欧美日韩精品| 午夜时刻免费入口| 亚洲电影一级片| 亚洲福利视频久久| 日本一区二区免费视频| 91成人短视频| 亚洲а∨天堂久久精品喷水| 亚洲最大视频网| 欧美成人精品一级| 日韩久久久久久| 亚洲一区二区三区四区精品| 成人自拍视频| 日韩一区和二区| 麻豆网站免费观看| 香蕉成人app| 欧美不卡123| 韩国三级hd中文字幕有哪些| 视频在线亚洲| 精品国产自在久精品国产| 无码人妻丰满熟妇啪啪网站| 99国产精品免费网站| 精品国产一区久久| 免费的av网站| 九九热线有精品视频99| 亚洲天堂av综合网| 人人艹在线视频| 亚洲国产精品91| 欧美极品美女电影一区| 日韩 国产 在线| 麻豆9191精品国产| 国产剧情日韩欧美| 999av视频| 成年人网站91| 欧美日韩另类综合| 天堂а√在线资源在线| 一区二区三区四区激情| 男人日女人逼逼| 日韩一区二区三区免费| 制服丝袜亚洲网站| 亚洲激情 欧美| 国内精品久久久久久久影视简单 | 免费亚洲婷婷| 国产欧洲精品视频| www.99视频| 91在线观看高清| 亚洲欧洲中文| 女人黄色免费在线观看| 色香色香欲天天天影视综合网| a在线观看免费视频| 中文无码日韩欧| 亚洲欧美福利视频| 国产性xxxx| 国产视频一区欧美| 国产欧美一区二区三区视频| 亚洲免费成人在线| 国产欧美日韩在线| 国产精品视频一二三四区| 中文字幕高清在线播放| 538prom精品视频线放| 免费观看一级一片| 希岛爱理av一区二区三区| 91av在线免费观看| 国产精品视频在线观看免费 | 人妻互换一区二区激情偷拍| 欧美阿v一级看视频| 国产www精品| 99国产在线播放| 国产调教视频一区| 男人c女人视频| 成人激情视屏| 日韩电影中文字幕| 国产十六处破外女视频| 日韩精品三区四区| 国产精品日韩高清| 好操啊在线观看免费视频| 一本一道波多野结衣一区二区| 91av免费观看| 9999国产精品| 国产精品91久久| 婷婷久久久久久| 亚洲精选一二三| 亚洲xxx在线观看| 九一成人免费视频| 97国产精品视频人人做人人爱| 国产精品一区二区黑人巨大| 国产清纯美女被跳蛋高潮一区二区久久w | 免费成人三级| 色综合久久悠悠| 国产精品无码专区av免费播放| 国产欧美视频在线观看| 久久精品免费一区二区| 久久动漫网址| 久久久久久12| 亚洲精品久久久蜜桃动漫| 日韩理论片网站| 亚洲欧美视频二区| 成人三级视频| 国产精品视频永久免费播放| 免费在线超碰| 91极品美女在线| 日韩精品无码一区二区三区久久久 | 日本在线观看视频网站| 国产寡妇亲子伦一区二区| 在线观看免费91| 欧洲午夜精品| 精品国产区一区二区三区在线观看| 欧美一级淫片免费视频黄| 97成人超碰视| 欧美 日韩精品| 亚洲涩涩av| 青青久久aⅴ北条麻妃| 神马久久精品| 色综合天天综合在线视频| 亚洲av无码一区二区二三区| 亚洲专区在线| 欧美午夜精品久久久久免费视| 成人影院大全| 一区二区三区国产在线观看| 中文字幕在线观看欧美| 国产精品久久久久一区| 在线观看免费不卡av| 中文字幕一区二区三区乱码图片| 99精品国产一区二区| 波多野结衣中文字幕久久| 日韩精品免费在线视频观看| www.久久久久久久| 一区在线观看视频| 国产一精品一aⅴ一免费| 在线成人国产| 日本精品一区二区| 国产日本久久| 日韩中文娱乐网| 超碰人人人人人人| 欧美性xxxx极品高清hd直播| 手机av在线不卡| 国产一区二区三区精品欧美日韩一区二区三区 | 69**夜色精品国产69乱| 国产精品久久久久久久龚玥菲| 欧美日韩国产大片| 久久久全国免费视频| 91在线视频播放| www.精品在线| 精品99视频| 色之综合天天综合色天天棕色| av在线成人| 68精品久久久久久欧美| 秋霞a级毛片在线看| 欧美精品一区二区三区在线| 国产伦精品一区二区三区视频我| 亚洲欧美乱综合| 香蕉视频黄色在线观看| 理论电影国产精品| 欧美精品久久久久久久免费| 超碰成人久久| 国产麻豆一区二区三区在线观看| 精品国模一区二区三区| 久久久久久国产精品久久| 国产原创av在线| 日韩欧美一区电影| 亚洲天堂网在线观看视频| 亚洲一区在线看| jizz18女人高潮| 99久久er热在这里只有精品66| 中文字幕第17页| 久久精品麻豆| 欧美一级视频在线播放| 国产精品久久久久蜜臀| 蜜桃av噜噜一区二区三区| 精品久久国产一区| 国产精品av在线播放| 99爱在线观看| 久热精品视频在线免费观看| 国产人成在线视频| 日韩h在线观看| www.亚洲欧美| 欧美一区二区日韩一区二区| 久久影视中文字幕| 欧美日韩精品国产| 久久精品免费在线| 亚洲免费色视频| 国产福利在线导航| 国产亚洲精品中文字幕| 一级欧美一级日韩片| 成人美女在线视频| 久久久无码人妻精品无码| 精品一区二区在线免费观看| 99免费视频观看| 国产日韩欧美一区| 毛片在线视频播放| 一区在线视频| 日韩a级在线观看| 欧美不卡视频| 真人做人试看60分钟免费| 91综合视频| 亚洲精品视频一二三| 欧美在线电影| 日韩中文不卡| av影片在线一区| 欧美一区二区三区在线免费观看| 日韩超碰人人爽人人做人人添| 国产精品免费一区二区三区| 综合久久成人| 国产精品免费在线播放| 国产一区在线电影| 国产日韩在线一区二区三区| 国产成人夜色高潮福利影视| 国产精品免费区二区三区观看 | 精品国产91乱码一区二区三区 | 91午夜视频在线观看| 亚洲成人免费电影| 国产又大又黄视频| 91电影在线观看| 中文在线免费看视频| 欧美日韩一二区| 国产精选久久久| 欧美一级欧美三级在线观看| 亚洲a视频在线| 亚洲精品国产欧美| 韩日视频在线| 日韩视频永久免费观看| av免费在线网站| 国内外成人免费激情在线视频| 俺来也官网欧美久久精品| 午夜欧美大片免费观看| 韩国美女久久| 国产精品综合网站| 欧洲大片精品免费永久看nba| 99影视tv| 伊人成综合网yiren22| 日韩妆和欧美的一区二区| 999视频精品| a级免费在线观看| 国产精品日韩| 污网站免费在线| 国产成人8x视频一区二区| 99久久人妻无码中文字幕系列| 国产亚洲成av人在线观看导航| 亚洲综合久久av一区二区三区| 夜夜爽夜夜爽精品视频| 国产黄色片免费看| 欧美日韩和欧美的一区二区| 999久久久久久| 亚洲美女中文字幕| 粗大黑人巨茎大战欧美成人| 97不卡在线视频| 国外成人福利视频| 国产精品久久久久免费| 精品国产乱码久久久久久蜜坠欲下 | 成人在线亚洲| www..com日韩| 久久se精品一区精品二区| 亚洲精品乱码久久| 亚洲欧美综合色| 亚洲天堂一区在线观看| 欧美精品乱码久久久久久| 人妻va精品va欧美va| 日韩在线不卡视频| www.成人影院| 成人av免费电影| 国产高清一区二区| 国产一区亚洲二区三区| 国产成人日日夜夜| wwwww黄色| 欧美性69xxxx肥| 好吊色在线观看| 久久精品国产一区二区电影| 依依综合在线| 国产精品精品软件视频| 国产精品成人a在线观看| 日韩av片在线看| 国产69精品一区二区亚洲孕妇| 人与嘼交av免费| 福利微拍一区二区| 99久久精品国产一区色| 在线国产精品视频| 我爱我色成人网| 精品国产乱码久久久久软件| 欧美激情一区| 免费网站在线观看黄| 国产亚洲一区二区三区在线观看| 日韩高清精品免费观看| 欧美mv和日韩mv国产网站| 国产精品一区二区三区视频网站| 国产精品成人品| 国产精品欧美在线观看| 91av资源网| 97久久精品人人做人人爽50路| 国产一级视频在线| 欧美一卡二卡在线| av免费看在线| 91啪国产在线| 亚洲精品久久| 北条麻妃亚洲一区| 综合自拍亚洲综合图不卡区| 一二三四区在线| 日韩中文字幕网站| 九九热这里有精品| 一区精品在线| 九九在线精品视频| 精品国产国产综合精品| 欧美二区三区91| 老司机福利在线视频| 91网站在线免费观看| 五月久久久综合一区二区小说| 欧美激情第3页| 国产精品不卡一区| 国产男男gay体育生白袜| 久久躁日日躁aaaaxxxx| 欧美专区视频| www插插插无码视频网站| 99久久99久久综合| 成人a v视频| 色多多国产成人永久免费网站| 亚洲人成网站在线在线观看| 超碰在线免费观看97| 国产91精品久久久久久久网曝门| 精品在线视频观看| 日韩精品极品在线观看播放免费视频| 超碰一区二区| 亚洲精蜜桃久在线| 国产一区二区电影| 国产亚洲欧美精品久久久久久 | 亚洲欧美亚洲| 黑森林av导航| 欧美性生交xxxxxdddd| 波多野结衣一区二区| 成人精品视频99在线观看免费| 国模 一区 二区 三区| jizz日本免费| 欧美午夜理伦三级在线观看| 精品视频在线一区二区| 国产精品一区免费观看| 石原莉奈在线亚洲三区| 99久久久无码国产精品不卡| 欧美一级久久久久久久大片| 国产激情视频在线看| 日韩激情久久| 丰满放荡岳乱妇91ww| 免费看日批视频| 精品国产一区二区三区久久久狼 | av白虎一区| 台湾成人av| 成人天堂资源www在线| 国产亚洲久一区二区| 欧美成人一区在线| 久久93精品国产91久久综合| 久久久久久久久久久久久久久国产| 亚洲已满18点击进入久久| 欧美视频综合| 亚洲一区二区久久久久久久| 久久av一区| 青青草原国产视频| 亚洲性线免费观看视频成熟| 亚洲视频国产| 狠狠操精品视频| 亚洲午夜久久久久中文字幕久|