scala之旅-核心语言特性【for comprehension 表达式】(十八)

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)
原文地址:https://www.cnblogs.com/zhouwenyang/p/13918203.html