本文 AI 產出,尚未審核

Golang 控制流程 – 條件判斷(if‑else、switch‑case)

簡介

在任何程式語言中,條件判斷都是決定程式執行路徑的核心機制。Go 語言以簡潔、直觀的語法提供 if‑elseswitch‑case,讓開發者能在保持程式可讀性的同時,快速完成分支邏輯。
掌握這兩種結構不只可以寫出正確的程式,更能提升程式的可維護性與效能,對於從新手晉升為中級開發者尤為重要。以下我們將深入探討 Go 的條件判斷寫法、常見陷阱與實務應用。

核心概念

1. ifelse 的基本語法

Go 的 if 語句不需要圓括號,條件表達式直接寫在 if 後;大括號則是必須的。

if x > 10 {
    fmt.Println("大於 10")
}

若需要多條件或先宣告變數,可在 if 前加上簡短的 短變數宣告(short variable declaration):

if n := len(s); n == 0 {
    fmt.Println("字串為空")
} else if n < 5 {
    fmt.Println("字串長度小於 5")
} else {
    fmt.Println("字串長度足夠")
}

重點:短變數宣告的作用域僅限於整個 if‑else 區塊,結束後即被釋放,避免變數污染。

2. 多層 if‑else 的寫法

在 Go 中,else 必須與前一個 if 的右大括號同一行,否則會產生編譯錯誤:

if score >= 90 {
    grade = "A"
} else if score >= 80 { // 正確寫法:else 必須接在 } 後面同一行
    grade = "B"
} else {
    grade = "C"
}

3. switch 的基本結構

switch 是多分支選擇的利器。Go 的 switch 不必寫 break,每個 case 執行完會自動跳出。若想要「fall‑through」必須顯式使用 fallthrough 關鍵字。

switch day {
case "Mon", "Tue", "Wed", "Thu", "Fri":
    fmt.Println("平日上班")
case "Sat", "Sun":
    fmt.Println("週末休息")
default:
    fmt.Println("未知的日期")
}

4. 表達式 switch(Switch without a condition)

省略條件式時,switch 會依序評估每個 case 的布林表達式,第一個為 true 的 case 會被執行,等同於 if‑else if‑else 鏈。

switch {
case age < 18:
    fmt.Println("未成年")
case age >= 18 && age < 65:
    fmt.Println("成年")
default:
    fmt.Println("高齡")
}

5. type switch – 依型別分支

在需要根據變數的實際型別做不同處理時,可使用 type switch

var v interface{} = getValue()
switch val := v.(type) {
case int:
    fmt.Printf("整數 %d\n", val)
case string:
    fmt.Printf("字串 %s\n", val)
default:
    fmt.Printf("其他型別 %T\n", val)
}

技巧type switch 常與 interface{} 搭配,用於 JSON 解析、通用函式等情境。

6. switch 中的 fallthrough

fallthrough 只會讓程式執行下一個 case 的語句,不會重新評估條件,因此使用時需特別小心。

switch n {
case 1:
    fmt.Println("一")
    fallthrough
case 2:
    fmt.Println("二") // 會被執行,即使 n != 2
default:
    fmt.Println("其他")
}

程式碼範例

範例 1:使用 if‑else 判斷使用者年齡

package main

import "fmt"

func main() {
    var age int
    fmt.Print("請輸入年齡: ")
    fmt.Scan(&age)

    if age < 0 {
        fmt.Println("年齡不可為負")
    } else if age < 18 {
        fmt.Println("未成年")
    } else if age < 65 {
        fmt.Println("成年人")
    } else {
        fmt.Println("高齡族群")
    }
}

說明:透過多層 else if,將年齡區間清晰分段,並在最前面先檢查不合理的負值。


範例 2:switch 判斷星期與工作排程

package main

import (
    "fmt"
    "time"
)

func main() {
    today := time.Now().Weekday() // 取得當前星期

    switch today {
    case time.Monday, time.Tuesday, time.Wednesday, time.Thursday, time.Friday:
        fmt.Println("今天是上班日")
    case time.Saturday:
        fmt.Println("今天是加班日")
    case time.Sunday:
        fmt.Println("今天是休息日")
    }
}

說明:利用 time.Weekday 常數直接對照,避免手寫字串比較,提高可讀性與安全性。


範例 3:表達式 switch 用於分級評分

package main

import "fmt"

func grade(score int) string {
    switch {
    case score >= 90:
        return "A"
    case score >= 80:
        return "B"
    case score >= 70:
        return "C"
    case score >= 60:
        return "D"
    default:
        return "F"
    }
}

func main() {
    fmt.Println("成績 85 => 等級", grade(85))
}

說明:省去重複的變數比較,讓程式更簡潔;default 處理所有未符合條件的分數。


範例 4:type switch 解析任意型別的 JSON 欄位

package main

import (
    "encoding/json"
    "fmt"
)

func main() {
    data := []byte(`{"id":123,"name":"Alice","active":true}`)

    var m map[string]interface{}
    json.Unmarshal(data, &m)

    for k, v := range m {
        switch val := v.(type) {
        case float64: // json 的數字預設是 float64
            fmt.Printf("%s 為數字: %.0f\n", k, val)
        case string:
            fmt.Printf("%s 為字串: %s\n", k, val)
        case bool:
            fmt.Printf("%s 為布林: %t\n", k, val)
        default:
            fmt.Printf("%s 為未知型別: %T\n", k, val)
        }
    }
}

說明:在處理動態結構(如 JSON)時,type switch 能快速分辨不同資料型別,避免手動斷言錯誤。


範例 5:switch 搭配 fallthrough 實作簡易的狀態機

package main

import "fmt"

func main() {
    state := 1

    switch state {
    case 1:
        fmt.Println("狀態 1:初始化")
        fallthrough
    case 2:
        fmt.Println("狀態 2:載入資源")
        fallthrough
    case 3:
        fmt.Println("狀態 3:執行中")
    default:
        fmt.Println("未知狀態")
    }
}

說明fallthrough 讓程式從狀態 1 直接跑到狀態 3,模擬「連續執行」的情境,但要注意 僅在確定需要此行為時使用,否則容易產生意外的邏輯錯誤。

常見陷阱與最佳實踐

陷阱 可能的問題 解決方案 / 最佳實踐
忘記 else 同行 編譯錯誤 expected else, found } else { 必須寫在同一行,或使用大括號包住整段 if‑else
if 中的短變數作用域誤用 變數在外層不可見,導致未宣告錯誤 確認需要的變數是否真的只在條件內使用,若需外部使用,改為先宣告再賦值
switch 中忘記 break Go 會自動跳出,若想手動中斷請使用 returngoto 了解 Go 的自動 break 行為,僅在真的需要 fallthrough 時才使用
fallthrough 濫用 造成不必要的 case 被執行,邏輯難以追蹤 僅在「必須」連續執行多個 case 時使用,並在註解說明原因
type switch 忽略 default 未處理未知型別會導致 panic 始終加入 default,即使只打印警告或回傳錯誤
switch 中使用複雜表達式 可讀性下降 若條件過於複雜,考慮改寫為 if‑else 或抽離為函式

其他最佳實踐

  1. 保持條件簡潔:每個 ifcase 只處理單一概念,避免「過長的條件」讓程式難以閱讀。
  2. 使用命名常數:對於 switch 中的固定值(如狀態碼、類型代號),使用 iotaconst 定義,提升可維護性。
  3. 避免在 case 中寫大量程式:若需要執行多行邏輯,建議抽成獨立函式,再在 case 內呼叫。
  4. 測試邊界值:尤其是 if‑else 的比較運算子(<, <=, >),務必寫測試覆蓋等於與不等於的情況。

實際應用場景

場景 為何使用 if‑else 為何使用 switch
API 請求參數驗證 需要逐一檢查多個欄位是否為空、格式是否正確,條件較為分散 若參數類型或狀態碼固定,可用 switch 快速分支
HTTP 狀態碼處理 只需要判斷 2xx、4xx、5xx 三大類,if 足以 若要對每個具體狀態碼(200、201、404、500)分別處理,switch 更直觀
業務規則引擎 複雜的條件組合(如金額 > X 且客戶等級 = A)適合 if 結合布林運算 若規則是「根據類別」的離散選擇(如商品類別),switch 更易維護
狀態機(State Machine) 簡單的二元切換(開/關)可用 if 多階段流程(Init → Load → Run → Stop)適合 switch + fallthroughtype switch
JSON/介面型別動態解析 需要先判斷是否為 nil、是否為字串等,if 先行檢查 真正根據型別分支時,type switch 為首選

總結

條件判斷是程式設計的基礎,也是控制流程的核心。Go 提供的 if‑elseswitch‑case,在語法上盡量減少冗餘(不需要圓括號與 break),同時保留了足夠的彈性:

  • if‑else:適合少數條件、需要先行變數宣告或布林運算的情境。
  • switch:適合多分支、離散值或型別判斷,且可透過 表達式 switchtype switch 處理更複雜的需求。

掌握上述概念、避免常見陷阱、遵循最佳實踐,能讓你寫出 可讀、可維護且效能良好 的 Go 程式。未來在開發 API、業務邏輯或大型系統時,條件判斷的正確運用將是提升開發效率與程式品質的關鍵。祝你在 Golang 的旅程中,寫出更乾淨、更可靠的程式碼!