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 <- userBase 是一个 List,并且因为我们说 yield user.name,其中 user.name 是一个 String,所以总体结果是一个 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)

更多资源

本页的贡献者