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)