1. 程式人生 > >scala語法 - 高階for迴圈:迴圈守衛、多表達式、yield關鍵字

scala語法 - 高階for迴圈:迴圈守衛、多表達式、yield關鍵字

1. 以符號 <- 提供生成器

// 基礎用法
for (i <- 1 to 3) {
  println(i)
}
RS:
1
2
3

2. 可以提供多個生成器,並以分號分隔

// 以 <- 變量表達式的形式,提供多個for迴圈,以;隔開
for (i <- 1 to 3; j <-1 to 3) {
  println(s"i=$i, j=$j, i+j=${i + j}")
}

println("*****")

//
for (i <- 1 to 3; j <-1 to 2) {
  println(s"i=$i, j=$j, i+j=${i + j}")
}

RS:
i=1, j=1, i+j=2
i=1, j=2, i+j=3
i=1, j=3, i+j=4
i=2, j=1, i+j=3
i=2, j=2, i+j=4
i=2, j=3, i+j=5
i=3, j=1, i+j=4
i=3, j=2, i+j=5
i=3, j=3, i+j=6
*****
i=1, j=1, i+j=2
i=1, j=2, i+j=3
i=2, j=1, i+j=3
i=2, j=2, i+j=4
i=3, j=1, i+j=4
i=3, j=2, i+j=5

3. 控制守衛

所謂控制守衛,即一個以if開頭的Boolean表示式

// 每個生成器可以帶上 "守衛",以 if 開頭的 Boolean表示式
for (i <- 1 to 3; j <-1 to 3 if i > j) {
  println(s"i=$i, j=$j, i+j=${i + j}")
}

RS:
i=2, j=1, i+j=3
i=3, j=1, i+j=4
i=3, j=2, i+j=5

注意:if前面沒有分號

4. 可以引入任意多的定義,並也可以再引入再迴圈中使用的變數

// 可以引入任意多的定義,並也可以再引入再迴圈中使用的變數
for (i <- 1 to 3; from = 5 - i; j <- from to 3){
  println(s"i=$i, from=$from, j=$j")
}

RS:
i=2, from=3, j=3
i=3, from=2, j=2
i=3, from=2, j=3

在上例中,引入變數from。第一次,i=1,那麼 from = 5-1=4,j<-4 to 3,這裡4 to 3不滿足定義了,直接跳出,進入第二次。第二次,i=2, from=5-2=3, j<- 3 to 3, 那麼就是3。後面依次類推

5. 迴圈體 yield

先來看看幾個Demo

// 迴圈體以yield開始
val a = for (i <- 1 to 10) yield i
print("a: "); println(a)

val aa = for (i <- "hello") yield i
print("aa: "); println(aa)

val b = for (i <- "hello"; j <- 1 to 3) yield (i + j)
print("b: "); println(b)

val ab = for (j <- 1 to 3; i <- "hello") yield (i + j)
print("ab: "); println(ab)

val c = for (i <- Map("A"->1,"b"->2)) yield i
print("c: "); println(c)

列印結果:
a: Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
aa: hello
b: Vector(105, 106, 107, 102, 103, 104, 109, 110, 111, 109, 110, 111, 112, 113, 114)
ab: Vector(105, 102, 109, 109, 112, 106, 103, 110, 110, 113, 107, 104, 111, 111, 114)
c: Map(A -> 1, b -> 2)

在《Programming Scala》中是這麼定義yield關鍵字的:

For each iteration of your for loop, yield generates a value which will be remembered. It’s like the for loop has a buffer you can’t see, and for each iteration of your for loop, another item is added to that buffer. When your for loop finishes running, it will return this collection of all the yielded values. The type of the collection that is returned is the same type that you were iterating over, so a Map yields a Map, a List yields a List, and so on.

Also, note that the initial collection is not changed; the for/yield construct creates a new collection according to the algorithm you specify.

也就是說:

  1. 每次for迴圈,yield會生成一個緩衝變數,當迴圈結束的時候,這些快取在buffer中的變數將會合並返回
  2. 返回的變數的型別與迴圈表示式中的型別一致

但是仔細觀察上面幾個Demo,不難發現在第二個特性中,返回值的型別是與第一個表示式的變數是一致的