scala中yield关键字

1,398 阅读2分钟

简介

对于for循环的每次迭代,yield都会生成一个将被记住的值。就像有一个你看不见的缓冲区,for循环的每一次迭代都会将另一个新的值添加到该缓冲区。

当for循环结束运行时,它将返回所有已赋值的集合。返回的集合的类型与迭代产生的类型相同,因此Map会生成Map,List将生成List,等等。

另外请注意,最初的集合没有改变。for / yield构造根据您指定的算法创建一个新的集合。

例子

基于上面的信息,来看几个例子:

scala> val a = Array(1, 2, 3, 4, 5)
a: Array[Int] = Array(1, 2, 3, 4, 5)

scala> for (e <- a) yield e
res5: Array[Int] = Array(1, 2, 3, 4, 5)

scala> for (e <- a) yield e * 2
res6: Array[Int] = Array(2, 4, 6, 8, 10)

scala> for (e <- a) yield e % 2
res7: Array[Int] = Array(1, 0, 1, 0, 1)

scala> val b = List(1, 2, 3, 4, 5)
b: List[Int] = List(1, 2, 3, 4, 5)

scala> for (e <- b) yield e
res8: List[Int] = List(1, 2, 3, 4, 5)

正如你所见, 例子中被 yield 的是 Array[Int],返回的也是Array[Int];被 yield 的是 List[Int],返回的也是List[Int]。

那么看看下面的例子:

scala> for (i <- 1 to 5) yield i
res10: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3, 4, 5)

scala> for (i <- 1 to 5) yield i * 2
res11: scala.collection.immutable.IndexedSeq[Int] = Vector(2, 4, 6, 8, 10)

scala> for (i <- 1 to 5) yield i % 2
res12: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 0, 1, 0, 1)

这儿yield的是一个range,但是产生的结果却是vector。这是因为Range是一个特殊的数据结构,用于保存等间隔的一列连续的数组,在这个数据结构上调用map或者yield等后,不能保证结果一定还是一个等间隔的一列连续的数组,那么结果当然也不能再是Range类型了。

于是就有了之前提到的implicit转化。

for循环, yield和guards

假如你熟悉了 Scala 复杂的语法, 你就会知道可以在 for 循环结构中加上 ‘if’ 表达式. 它们作为测试用,通常被认为是一个guards,你可以把它们与 yield 语法联合起来用。

scala> val a = Array(1, 2, 3, 4, 5)
a: Array[Int] = Array(1, 2, 3, 4, 5)

scala> for (e <- a if e > 2) yield e
res1: Array[Int] = Array(3, 4, 5)```