1. 程式人生 > 實用技巧 >scala之旅-核心語言特性【for 直譯器】(十八)

scala之旅-核心語言特性【for 直譯器】(十八)

Scala提供了一個用於解析迴圈的輕量級語法。解析的格式為 for (enumerators) yield e,這裡的enumerators 表示用逗號分割的列舉列表。 一個enumerator 可以是介紹變數的生成器,也可以是一個過濾器。直譯器會給每個繫結生成的enumerators生成一個主體 e ,並以一個序列的形式返回。

例子如下:

case class User(name: String, age: Int)

val userBase = List(
  User("Travis", 28),
  User("Kelly", 33),
  User("Jennifer", 44),
  User(
"Dennis", 23)) val twentySomethings = for (user <- userBase if user.age >=20 && user.age < 30) yield user.name // i.e. add this to a list twentySomethings.foreach(name => println(name)) // prints Travis Dennis

for 迴圈組合yield 語句會返回一個結果,這個返回結果的型別由第一個生成器決定。 user <- userBase 是一個 list ,因為我們宣告的是 yeild user.name 而user.name 是一個String 型別,所以返回的是一個 List[String] 型別。然後我們使用if user.age >=20 && user.age < 30 用於過濾年齡不在20到30歲之間的使用者。

下面是一個兩個生成器的推薦做法。這個例子計算了0~n-1之間和為v 的一對數。

def foo(n: Int, v: Int) =
   for (i <- 0 until n;
        j <- 0 until n if i + j == v)
   yield (i, j)

foo(10, 10) foreach {
  case (i, j) =>
    println(s"($i, $j) ")  // prints (1, 9) (2, 8) (3, 7) (4, 6) (5, 5) (6, 4) (7, 3) (8, 2) (9, 1)
}

這裡的 n和v 都為10。在第一個遍歷中,i==0 且 j==0 所以i+j != v所以因為yeild 沒有返回任何東西 。j 在 i 增加到1之前,會先自增個9次以上。 如果沒有 if,輸出結果會如下顯示:

(0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (0, 5) (0, 6) (0, 7) (0, 8) (0, 9) (1, 0) ...

直譯器不僅僅限於列表。 任何支援 withFilter,map 和 flatMap (具有明確型別的) 都可以被用到序列解釋。

你可以在直譯器中省略 yield。這時候,直譯器將返回 Unit。這段程式等價於之前沒有用yield:

def foo(n: Int, v: Int) =
   for (i <- 0 until n;
        j <- 0 until n if i + j == v)
   println(s"($i, $j)")

foo(10, 10)