scala之旅-核心語言特性【for 直譯器】(十八)
阿新 • • 發佈:2020-11-03
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)