Scala 導覽

對於理解

語言

Scala 提供一種輕量級表示法來表達序列理解。理解具有 for (enumerators) yield e 的形式,其中 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(println)  // prints Travis Dennis
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(println)  // prints Travis Dennis

一個包含 yield 陳述式的 for 迴圈會傳回一個結果,其容器類型由第一個產生器決定。 user <- userBaseList,而且因為我們說 yield user.name,其中 user.nameString,因此整體結果是 List[String]。而 if user.age >=20 && user.age < 30 是用來過濾掉未滿二十歲的使用者。

以下是使用兩個產生器的更複雜範例。它會計算介於 0n-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)
}
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 {
  (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 == 10v == 10。在第一次反覆運算時,i == 0j == 0,因此 i + j != v,因此不會產生任何結果。在 i 增加到 1 之前,j 會再增加 9 次。如果沒有 if 保護,這只會印出以下內容

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

請注意,推導式不限於清單。每個支援 withFiltermapflatMap(具有適當類型)運算的資料類型都可以在序列推導式中使用。

您可以在推導式中省略 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)
def foo(n: Int, v: Int) =
   for i <- 0 until n
       j <- 0 until n if i + j == v
   do println(s"($i, $j)")

foo(10, 10)

更多資源

  • Scala Book 中「For 推導式」的其他範例

此頁面的貢獻者