Go 的 for 迴圈進階寫法
Go 的設計哲學是「少即是多」,因此沒有 while 或 do-while,所有迴圈都由 for 一手包辦。以下整理幾種在實務中常見、道地(Idiomatic)的進階寫法。
1. 略過不需要的變數(Blank Identifier)
使用 range 時若不需要 index 或 value,不能留空(Go 會編譯報錯),需用底線 _ 略過:
// 只想要 value,不想要 index
for _, v := range s2 {
fmt.Println(v)
}
// 只想要執行次數,不需要內容
for range s2 {
doSomething()
}
2. 同時遍歷兩個變數
for 的初始化區塊可宣告多個變數,適合雙指標或同步計數:
for i, j := 0, 10; i < j; i, j = i+1, j-1 {
fmt.Printf("i: %d, j: %d\n", i, j)
}
3. Range 的「值複製」陷阱
在 range 迴圈中,value 是原始元素的複製品,修改它不會影響原本的 slice。
| 寫法 | 結果 |
|---|---|
| 錯誤 | v = v * 10 → slice 不變 |
| 正確 | s2[i] = s2[i] * 10 → 直接改到 slice |
for i, v := range s2 {
v = v * 10 // 無效,改的是複本
s2[i] = s2[i] * 10 // 有效,改的是原 slice
}
4. 搭配 Select 處理 Channel
併發情境下常用 for + select 持續監聽多個 channel:
for {
select {
case msg := <-ch:
fmt.Println("收到訊息:", msg)
case <-done:
return
}
}
5. 標籤(Label)跳出外層迴圈
巢狀迴圈時,可用 Label 從內層直接 break 到外層:
OuterLoop:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break OuterLoop
}
}
}
總結
- 優先使用
range:可讀性高、字串會按 rune 遍歷(正確處理 UTF-8)、可避免 off-by-one 錯誤。 - 要改 slice 元素時,用 index 存取
s[i],不要改range回傳的 value。