鍍金池/ 教程/ Scala/ for 表達式
包對象
Ordered Trait
組合和繼承–定義 final 成員
基本數(shù)據(jù)類型
Match 表達式
類和對象 (三)
操作基本數(shù)據(jù)類型
for 表達式
組合和繼承–重載成員函數(shù)和方法
類和對象 (二)
組合和繼承–定義 factory 對象
組合和繼承–多態(tài)和動態(tài)綁定
Trait 的基本概念
if 表達式
組合和繼承–抽象類
函數(shù)–函數(shù)字面量的一些簡化寫法
while 循環(huán)
組合和繼承–使用組合還是繼承?
訪問控制修飾符
Trait 示例–Rectangular 對象
組合和繼承–定義參數(shù)化成員變量
組合和繼承–定義無參數(shù)方法
類和對象 (一)
函數(shù)–閉包
函數(shù)–類成員函數(shù)
Scala 基本數(shù)據(jù)類型的實現(xiàn)方法
try 表達式處理異常
選擇瘦接口還是胖接口設(shè)計?
組合和繼承–小結(jié)
創(chuàng)建新的控制結(jié)構(gòu)
使用 import
為訪問控制修飾符添加作用域
Scala 的類層次關(guān)系
類和對象 (五)
傳名參數(shù)
柯里化函數(shù)
函數(shù)–頭等公民
組合和組合和繼承–定義 heighten 和 widen 函數(shù)
使用 Package–將代碼放入包中
隱含的 import
所有類的公共子類–底層類型
進一步 Scala
函數(shù)–局部函數(shù)
引用包中的代碼
組合和繼承–使用 override 修飾符
組合和繼承–實現(xiàn)類 Element 的 above,beside 和 toString()方法
類和對象 (四)
函數(shù)–尾遞歸
沒有“break”和“continue”的日子
組合和繼承–調(diào)用基類構(gòu)造函數(shù)
減低代碼重復(fù)
函數(shù)–函數(shù)–可變參數(shù),命名參數(shù),缺省參數(shù)
起步 Scala
組合和繼承–擴展類
函數(shù)–部分應(yīng)用的函數(shù)
開始神奇的 Scala編程之旅
組合和繼承–概述
Trait 用來實現(xiàn)可疊加的修改操作

for 表達式

Scala 中的 for 表達式有如一把完成迭代任務(wù)的瑞士軍刀,它允許你使用一些簡單的部件以不同的方法組合可以完成許多復(fù)雜的迭代任務(wù)。簡單的應(yīng)用比如枚舉一個整數(shù)列表,較復(fù)雜的應(yīng)用可以同時枚舉多個不同類型的列表,根據(jù)條件過濾元素,并可以生成新的集合。

枚舉集合元素

這是使用 for 表示式的一個基本用法,和 Java 的 for 非常類似,比如下面的代碼可以枚舉當前目錄下所有文件:

val filesHere = (new java.io.File(".")).listFiles
for( file <-filesHere)
  println(file)

其中如 file < – filesHere 的語法結(jié)構(gòu),在 Scala 中稱為“生成器 (generator)”。 本例中 filesHere 的類型為 Array[File],每次迭代 變量 file 會初始化為該數(shù)組中一個元素, File 的 toString()為文件的文件名,因此 println(file)打印出文件名。 Scala 的 for 表達式支持所有類型的集合類型,而不僅僅是數(shù)組,比如下面使用 for 表達式來枚舉一個 Range 類型。

 scala> for ( i      | println ("Interation " + i)
Interation 1
Interation 2
Interation 3
Interation 4

過濾

某些時候,你不想枚舉集合中的每個元素,而是只迭代某些符合條件的元素,在 Scala 中,你可以為 for 表達式添加一個過濾器–在 for 的括號內(nèi)添加一個 if 語句,例如:修改前面枚舉文件的例子,改成只列出 .scala 文件如下:

val filesHere = (new java.io.File(".")).listFiles
for( file   println(file)

如果有必要的話,你可以使用多個過濾器,只要添加多個 if 語句即可,比如,為保證前面列出的文件不是目錄,可以添加一個 if,如下面代碼:

val filesHere = (new java.io.File(".")).listFiles
for( file <-filesHere
   if file.isFile
   if file.getName.endsWith(".scala")
)  println(file)

嵌套迭代

fo r表達式支持多重迭代,下面的例子使用兩重迭代,外面的循環(huán)枚舉 filesHere,而內(nèi)部循環(huán)枚舉該文件的每一行文字。實現(xiàn)了類似 Unix grep 命令:

val filesHere = (new java.io.File(".")).listFiles
def fileLines (file : java.io.File) =
   scala.io.Source.fromFile(file).getLines().toList
def grep (pattern: String) =
  for (
    file     if file.getName.endsWith(".scala");
    line <-fileLines(file)
    if line.trim.matches(pattern)
  ) println(file + ":" + line.trim)
grep (".*gcd.*")

注意上面代碼中兩個迭代之間使用了”;”,如果你使用{} 替代 for 的()的括號,你可以不使用“;”分隔這兩個“生成器”,這是因為 Scala 編譯器不推算包含在括號內(nèi)的省掉的“;”。使用{}改寫的代碼如下:

val filesHere = (new java.io.File(".")).listFiles
def fileLines (file : java.io.File) =
   scala.io.Source.fromFile(file).getLines().toList
def grep (pattern: String) =
  for {
    file     if file.getName.endsWith(".scala")
    line <-fileLines(file)
    if line.trim.matches(pattern)
  } println(file + ":" + line.trim)
grep (".*gcd.*")

這兩段代碼是等效的。

綁定中間變量

你可以注意到前面代碼使用了多次 line.trim,如果 trim 是個耗時的操作,你可以希望 trim 只計算一次,Scala 允許你使用=號來綁定計算結(jié)果到一個新變量。綁定的作用和 val 類似,只是不需要使用 val 關(guān)鍵字,例如,修改前面的例子,只計算一次 trim,把結(jié)果保存在 trimmed 變量中。

val filesHere = (new java.io.File(".")).listFiles
def fileLines (file : java.io.File) =
   scala.io.Source.fromFile(file).getLines().toList
def grep (pattern: String) =
  for {
    file     if file.getName.endsWith(".scala")
    line <-fileLines(file)
    trimmed=line.trim
    if trimmed.matches(pattern)
  } println(file + ":" + trimmed)
grep (".*gcd.*")

生成新集合

for 表達式也可以用來生產(chǎn)新的集合,這是 Scala 的 for 表達式比 Java 的 for 語句功能強大的地方。它的基本語法如下:

for clauses yield body

關(guān)鍵字 yield 放在 body 的前面,for 沒迭代一次,產(chǎn)生一個 body,yield 收集所有的 body 結(jié)果,返回一個 body 類型的集合。比如,前面列出所有 .scala 文件,返回這些文件的集合:

def scalaFiles =
  for {
    file     if file.getName.endsWith(".scala")
  } yield file

scalaFiles 的類型為 Array[File]。