昨天學習在 Go 語言中 if ... else 及 switch...case 的條件判斷,今天就進入到迴圈的懷抱吧!
我之前曾做過秘書,每個月的月初都是我的惡夢,因為要協助計算員工薪水,其實計算的公式就是固定的,但每個月每人的業績一定不可能一樣,所以我總是花很多時間,在一一重複計算那些不屬於我的錢錢,啊如果是算我自己的薪水,我大概會樂此不疲,在我學習到迴圈之後,覺得曾經的我真的是太年輕了,迴圈是可以把需要重複執行的某些程式,根據你給他的輸入重複執行,且輸出結果,所以意思是我寫好計算公式,把大家的業績丟進去,然後去吃個下午茶,回來薪水會自己算好在我面前。用一個很有畫面的切身之痛,來告訴大家迴圈是多方便的好東西。
for 迴圈通常是用來處理有序的集合,如:1 加到 100。先來看看使用方式,再來一一解釋吧!
for <起始賦值敘述>; <條件敘述>; <結束敘述> {
<程式碼區塊>
}
上面是最標準的 for 迴圈,但其實省略部分的 for 迴圈也是可以的,以下示範幾個簡化的寫法
for {
<程式碼區塊>
}
三者都省略,等同於 for true 就會一直執行,而這樣會造成無窮迴圈,若想終止這個 for 迴圈,需要加上 break ,來跳出無窮迴圈。
for <條件敘述> {
<程式碼區塊>
}
此種 for 迴圈,較常用在讀取資料,如: 資料庫、檔案或 API 等等,從資料傳回的布林值,來判斷迴圈結束與否,所以我們並不用另外給予起始賦值敘述或結束敘述。
for <鍵>, <值> := range <集合> {
<程式碼區塊>
}
一開始介紹時有說過 for 迴圈通常是用來處理有序的集合,故若是遇到這種沒有順序的資料,如:映射表(maps),我們會改用 range 敘述,在後面章節會有對於 map 的詳細介紹,這邊只需要先知道有這個寫法。
我們經常使用 i( = 索引值 index ) 來作為 for 迴圈內的變數(當然你想要取名為 abc 也是可以的,但我們不太會取這種意義不明的名字),而這個 i 變數的作用範圍 scope 是只有存在於 for 迴圈內的,此種迴圈很適合用來處理用數字作為索引的有序集合,如:陣列、切片等等,以下示範使用 for 迴圈,一般累加變數及切片元素。
範例 1:
package main
import "fmt"
func main(){
for i := 1; i <= 5; i++{
fmt.Println(i)
}
}
範例 1(執行結果):
1
2
3
4
5
範例 2:
package main
import "fmt"
func main(){
favoriteFruit := []string{"apple","kiwi","peach","mango"}
for i := 0; i < len(favoriteFruit); i++ { // len() 可以取得任意集合的長度,索引值從 0 起累加,用 len() 的回傳值即可判定迴圈是否走到最後一個值,是否繼續執行或是終止。
fmt.Println(favoriteFruit[i])
}
}
範例 2(執行結果):
apple
kiwi
peach
mango
?補充:
若 len() 回傳集合長度為 N ,則該集合的最後一個元素即為 N-1。
在範例二我們試著用 for 迴圈走訪有序的切片,像是切片或是陣列裡的索引值都是有順序的從 0 開始,但在 map 裡就不一樣,因為 map 的鍵 (key) 與值 (value) 並不會按照順序排列,如果我們使用 for i 迴圈,因為不是按照順序的,是會拿取到錯誤順序的資料,所以這時就需要 range 。 range 是每次從集合取出一個鍵 (key) 與值 (value) ,而下一輪迴圈就換下一組,且在使用 range 敘述時,不需要結束敘述,因為在取完集合的所有值,便會自動結束迴圈。
?補充:
map 中元素是隨機排列的,本是為了防止開發人員仰賴元素順序來取值,但反過來說,你也可以使用 map 來模擬資料隨機排序。
範例 3:
package main
import "fmt"
func main(){
myFavorite := map[string]string{
"fruit":"mango",
"animal":"panda",
"dessert":"cheesecake"
}
for key, value := range myFavorite{
fmt.Println("key:",key," = value:",value)
}
}
範例 3(執行結果):
key: fruit = value: mango
key: animal = value: panda
key: dessert = value: cheesecake
?補充:
在 range 中,若不需要用到 key, value 是都可以省略的,只需要改成底線字元 _ 或直接省略即可。
範例 4:
package main
import "fmt"
func main(){
myFavorite := map[string]string{
"fruit":"mango",
"animal":"panda",
"dessert":"cheesecake"
}
for _, value := range myFavorite { // key 因為不需要用到,改成 _
fmt.Println(value)
}
}
範例 4(執行結果):
mango
panda
cheesecake
範例 5:
package main
import "fmt"
func main(){
myFavorite := map[string]string{
"fruit":"mango",
"animal":"panda",
"dessert":"cheesecake"
}
for key := range myFavorite{ // value 沒有需要用掉,可直接省略,或等同於 for key, _ := range myFavorite
fmt.Println(key)
}
}
範例 5(執行結果):
fruit
animal
dessert
?補充:
range 敘述也可以用於陣列或切片,此時 key 會是索引值, value 是元素值,這樣一來就跟 for i 的效果相同,且不用自己計算長度,以及程式碼會變得簡潔,唯一的缺點是無法使用 map 來修改原集合的 value,因為 value 是在迴圈中建立的變數,跟外面的原集合是沒有關係的。
範例 6:
package main
import "fmt"
func main(){
favoriteFruit := []string{"apple","kiwi","peach","mango"}
for i , value := range favoriteFruit{
fmt.Println("index:",i,"value:",value)
}
}
範例 6(執行結果):
index: 0 value: apple
index: 1 value: kiwi
index: 2 value: peach
index: 3 value: mango
上面有說到的,若是不小心寫出無窮迴圈,我們需要直接讓這個迴圈停止,這時便可以使用 break 來終止迴圈並跳出,當然也可以寫一個判斷,在特定狀況下跳出迴圈。
continue 跟 break 的差別就在於,符合判斷的 continue 會終止這輪迴圈,然後再進入新的下一輪的迴圈。
範例 7:
package main
import (
"fmt"
"math/rand"
)
func main(){
for{
i := rand.Intn(10) // 產生 0~10 的亂數
if i%3 == 0 { // 若是 3 的倍數
fmt.Println("i=",i,",用 continue 來跳過這次迴圈")
continue
} else if i%2 == 0 { // 若是 2 的倍數
fmt.Println("i=",i,",用 break 來終止這次迴圈")
break
}
fmt.Println("i=",i)
}
}
範例 7(執行結果):
i= 1
i= 7
i= 7
i= 9 ,用 continue 來跳過這次迴圈
i= 1
i= 8 ,用 break 來終止這次迴圈
這裡我們省略起始賦值敘述、條件敘述及結束敘述的 for 無窮 迴圈,但是加上 continue 和 break,限制這個無窮迴圈,便可以讓這個迴圈有終止。
今天學習到了在 Go 語言中的迴圈,明天繼續來介紹 Go 語言中有哪些核心型別吧!