Skip to content

第03章 流程控制 —— if、for、switch

本章目标:掌握 Go 的三大流程控制工具,能写出有判断、能循环的真实程序。


1. 流程控制的本质

🌰 生活化比喻:写程序就像写菜谱

  • 顺序执行:第一步、第二步、第三步……(默认)
  • 条件判断:if 鸡蛋打散了,就 ……
  • 循环执行:for 锅里水开之前,一直加柴
  • 分支选择:switch 看食材是什么,决定怎么炒

📊 配套图解:diagrams/control-flow-overview.svg


2. if 语句

2.1 基本形式

go
if score >= 60 {
    fmt.Println("及格")
} else if score >= 90 {
    fmt.Println("优秀")
} else {
    fmt.Println("不及格")
}

注意:Go 中 if 后面不需要括号,但 { 必须紧贴条件。

2.2 if 的"小特权":初始化语句

go
if num, err := strconv.Atoi(s); err == nil {
    fmt.Println("解析成功:", num)
} else {
    fmt.Println("解析失败:", err)
}

🌰 生活化比喻:相当于"先洗手,再吃饭"——numerr 只在 if 块内有效。

这是 Go 推荐的写法,能让变量作用域最小化。


3. for 循环:唯一的循环关键字

Go 没有 while,没有 do-while只有一个 for,但可以变出多种花样。

3.1 三段式(C 风格)

go
for i := 0; i < 10; i++ {
    fmt.Println(i)
}

3.2 单条件(while 风格)

go
n := 0
for n < 100 {
    n += 7
}

3.3 死循环

go
for {
    // 无限循环,直到 break
}

3.4 range 遍历(最常用)

go
nums := []int{10, 20, 30}
for i, v := range nums {
    fmt.Println(i, v)
}

m := map[string]int{"a": 1, "b": 2}
for key, value := range m {
    fmt.Println(key, value)
}

s := "Hello"
for idx, r := range s {
    fmt.Printf("%d=%c\n", idx, r)
}

📊 配套图解:diagrams/for-styles.svg

3.5 breakcontinue

go
for i := 0; i < 10; i++ {
    if i == 5 { break }      // 直接跳出
    if i % 2 == 0 { continue } // 跳过本次
    fmt.Println(i)
}

3.6 标签跳转(少用)

go
outer:
for i := 0; i < 3; i++ {
    for j := 0; j < 3; j++ {
        if i*j > 4 {
            break outer   // 跳出外层
        }
    }
}

4. switch:比 if-else 更优雅

4.1 基本形式

go
switch day {
case "Mon", "Tue", "Wed", "Thu", "Fri":
    fmt.Println("工作日")
case "Sat", "Sun":
    fmt.Println("周末")
default:
    fmt.Println("未知")
}

4.2 Go 的 switch 不像 C:默认不穿透

go
switch n {
case 1:
    fmt.Println("一")
    // 没写 break,但不会执行下一个 case!
case 2:
    fmt.Println("二")
}

🌰 生活化比喻:C 的 switch 像多米诺骨牌,撞倒第一张就连续倒;Go 像电梯,到一层就停。如果你真想"穿透",用 fallthrough

go
switch n {
case 1:
    fmt.Println("一")
    fallthrough
case 2:
    fmt.Println("二")   // 1 也会触发这里
}

4.3 没有条件的 switch(替代复杂 if-else)

go
switch {
case score >= 90:
    fmt.Println("优秀")
case score >= 60:
    fmt.Println("及格")
default:
    fmt.Println("挂科")
}

🌰 这相当于 switch true {...},每个 case 都是布尔表达式。

4.4 类型 switch(第07章会深入讲)

go
switch v := x.(type) {
case int:
    fmt.Println("整数", v)
case string:
    fmt.Println("字符串", v)
default:
    fmt.Println("未知类型")
}

📊 配套图解:diagrams/switch-anatomy.svg


5. goto:能不用就不用

go
goto END
fmt.Println("这行不会执行")
END:
fmt.Println("跳过来了")

⚠️ 不要用 goto ——破坏代码结构。Go 保留它主要是为了某些底层场景(如错误清理)。


6. 综合案例:FizzBuzz

go
package main

import "fmt"

func main() {
    for i := 1; i <= 30; i++ {
        switch {
        case i%15 == 0:
            fmt.Println("FizzBuzz")
        case i%3 == 0:
            fmt.Println("Fizz")
        case i%5 == 0:
            fmt.Println("Buzz")
        default:
            fmt.Println(i)
        }
    }
}

经典面试题:1-100 数字,3 的倍数打印 Fizz,5 的倍数打印 Buzz,15 的倍数打印 FizzBuzz。这道题考察的就是流程控制。


7. 本章小结

✅ Go 的 if 不需要括号,但 { 必须同行
if x := ...; cond { ... } 是 Go 推荐写法
✅ 只有 for,但能模拟 while、do-while、死循环
for range 是遍历切片、map、字符串的标准方式
switch 默认不穿透,需要 fallthrough 才穿透
✅ 用无条件 switch 替代长 if-else 链
✅ 不要用 goto,保留它只是历史包袱


📂 配套资源