本文 AI 產出,尚未審核

Golang – 控制流程

迴圈(forrangebreakcontinue


簡介

在任何程式語言中,迴圈都是實作重複性工作、遍歷資料集合、或是等待條件變化的核心工具。Go 語言把迴圈的語法設計得極為簡潔,只有單一關鍵字 for,卻能涵蓋傳統的 whiledo‑while 以及 foreach 等所有情境。了解 forrangebreakcontinue 的使用方式,不僅能寫出可讀性高的程式碼,還能避免常見的效能與邏輯陷阱,讓你的 Go 程式在 可維護性執行效率 上都有明顯提升。

本篇文章將從最基本的 for 語法說起,逐步帶入 range 的遍歷技巧、break/continue 的流程控制,以及實務上常見的使用情境與最佳實踐,適合剛踏入 Go 世界的初學者,也能為已有基礎的開發者提供系統性的回顧與進階觀點。


核心概念

1. 基本的 for 迴圈

Go 沒有 whiledo‑while,所有迴圈都以 for 表示。最簡單的寫法如下:

for i := 0; i < 10; i++ {
    fmt.Println(i)
}
  • 初始化 (i := 0) 只會在迴圈開始時執行一次。
  • 條件判斷 (i < 10) 每次迭代前都會評估,若為 false 則跳出迴圈。
  • 後置語句 (i++) 在每次迭代結束後執行。

變形:省略部份

// 只寫條件,相當於 while
for i < 5 {
    fmt.Println(i)
    i++
}

// 無條件迴圈,等同於 for(;;) → infinite loop
for {
    // 必須在某個條件下使用 break 離開
}

2. range:遍歷切片、陣列、字典與通道

range 讓我們可以一次取得 索引(或鍵)與 ,語法如下:

// 切片
nums := []int{2, 4, 6, 8}
for idx, val := range nums {
    fmt.Printf("第 %d 個元素 = %d\n", idx, val)
}

// 只要值
for _, val := range nums {
    fmt.Println(val) // 忽略索引
}

// 字典
m := map[string]int{"apple": 3, "banana": 5}
for key, value := range m {
    fmt.Printf("%s 有 %d 個\n", key, value)
}

// 通道 (channel)
ch := make(chan string, 3)
ch <- "golang"
ch <- "loop"
ch <- "range"
close(ch)

for msg := range ch {
    fmt.Println("收到訊息:", msg)
}
  • 切片/陣列range 會回傳索引與對應的值。
  • 字典:回傳鍵與值,遍歷順序是隨機的(不保證穩定)。
  • 通道range 會持續接收,直到通道被關閉。

小技巧:若只需要索引或值,使用底線 _ 佔位,可避免不必要的變數分配。


3. breakcontinue:細部控制迴圈流程

關鍵字 功能 常見用途
break 立即跳出最近一層的迴圈 找到目標後停止搜尋
continue 跳過本次迭代的剩餘程式,直接進入下一輪條件判斷 篩選不符合條件的資料

範例:使用 break 提前結束搜尋

func findFirstEven(nums []int) (int, bool) {
    for i, v := range nums {
        if v%2 == 0 {
            return i, true // 找到即回傳
        }
    }
    return -1, false // 沒有偶數
}

範例:使用 continue 跳過不需要的元素

func printOdd(nums []int) {
    for _, v := range nums {
        if v%2 == 0 {
            continue // 偶數直接略過
        }
        fmt.Println(v) // 只會印出奇數
    }
}

多層迴圈與標籤 (label):精準控制

outer:
for i := 0; i < 5; i++ {
    for j := 0; j < 5; j++ {
        if i*j > 6 {
            fmt.Printf("break outer at i=%d, j=%d\n", i, j)
            break outer // 跳出外層迴圈
        }
    }
}

注意:標籤只能用於 breakcontinue,且必須寫在同一個函式內,過度使用會降低程式可讀性,僅在確實需要「跳出多層迴圈」時才使用。


4. 迴圈的效能小提醒

  1. 避免在迴圈內重複建立大物件:如 make([]int, 0, 1000) 放在迴圈外,或使用 sync.Pool 重新利用記憶體。

  2. range 取得的切片值是****值的拷貝,若要修改原始元素,必須使用索引:

    for i := range nums {
        nums[i] *= 2 // 正確:直接改變原始 slice
    }
    
  3. 字典遍歷不保證順序,若需要穩定順序,先把鍵收集起來並排序:

    keys := make([]string, 0, len(m))
    for k := range m {
        keys = append(keys, k)
    }
    sort.Strings(keys)
    for _, k := range keys {
        fmt.Println(k, m[k])
    }
    

常見陷阱與最佳實踐

陷阱 說明 解決方式
忘記 break/continue 的標籤 多層迴圈時直接寫 break 只會跳出內層,導致邏輯錯誤。 使用 label(如 outer:)或重新設計為單層迴圈 + 條件判斷。
range 迭代字典時的隨機順序 期望固定順序卻得到不一致結果。 先收集鍵並排序,再依序取值。
for 迴圈裡改變切片長度 可能導致索引越界或遺漏元素。 使用 for i := 0; i < len(s); i++ { … } 並在迴圈內適時更新 len(s),或使用 append 後重新取得長度。
for range 中取得指標 range 產生的值是臨時變數,取地址會得到同一個指標。 直接使用索引取得指標:for i := range slice { p := &slice[i] }
過度使用 break/continue 使程式流程斷斷續續,降低可讀性。 盡量以條件式包住需要執行的區塊,讓迴圈本身保持線性。

最佳實踐

  • 明確命名迭代變數:如 idx, valkey, value,避免使用單字母 iv 以外的情況,提升可讀性。
  • 盡量避免在迴圈內做 I/O(例如 fmt.Println),除非真的需要即時輸出,否則可先收集結果再一次性輸出,減少系統呼叫成本。
  • 使用 go vetstaticcheck 檢查迴圈中可能的錯誤(如未使用的索引、指標誤用)。
  • 在需要大量計算的迴圈裡,考慮使用 goroutine + channel 進行平行化,但要注意競爭條件與同步成本。

實際應用場景

  1. 批次資料處理
    讀取 CSV 檔案後,用 for range 逐行解析、過濾、轉換,最後一次性寫入資料庫。

  2. 網路服務的請求佇列
    使用緩衝通道 chan Requestfor req := range requestCh { handle(req) } 持續處理進來的請求,break 用於服務關閉時安全退出。

  3. 搜尋與篩選
    在大型切片中找出符合條件的第一筆資料,使用 break 立即停止迭代,降低不必要的遍歷成本。

  4. 計算統計指標
    例如計算一段時間內的最大、最小、平均值,常見寫法:

    var sum, max, min int
    for i, v := range data {
        sum += v
        if i == 0 || v > max {
            max = v
        }
        if i == 0 || v < min {
            min = v
        }
    }
    avg := float64(sum) / float64(len(data))
    
  5. 遞迴轉迭代
    將遞迴演算法(如樹的深度優先搜尋)改寫成 for + stack,避免呼叫堆疊過深導致 panic。


總結

  • Go 只提供 單一關鍵字 for,即可完成 whiledo‑whileforeach 等所有迴圈需求。
  • range 是遍歷 切片、陣列、字典、通道 的利器,配合索引/值或僅值的寫法,可大幅簡化程式碼。
  • breakcontinue 讓我們在迴圈內精確控制流程,必要時可使用 標籤 跳出多層迴圈。
  • 了解常見陷阱(如字典遍歷順序、切片指標取得方式)與最佳實踐(避免不必要的 I/O、適時使用 sync.Pool)能提升程式的可讀性效能
  • 在實務開發中,迴圈是 資料處理、網路服務、演算法實作 的核心工具,熟練掌握後,寫出乾淨、快速且易於維護的 Go 程式將不再是難事。

把握這些概念,從今天起就能在 Go 專案中自信地使用迴圈,讓程式碼更簡潔、更高效!