跳到主要内容

Go 控制流

本章将介绍 Go 语言中的控制流语句,包括条件语句和循环。

if 语句

基本语法

if 条件 {
// 条件为 true 时执行
}

示例

age := 18

if age >= 18 {
fmt.Println("成年了")
}

if-else 语句

age := 16

if age >= 18 {
fmt.Println("成年了")
} else {
fmt.Println("未成年")
}

if-else if-else 语句

score := 85

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

简短语句

if 语句可以在条件前执行一个简短语句:

if age := 18; age >= 18 {
fmt.Println("成年了")
}

// age 在这里不可用

多条件判断

score := 75
attendance := true

if score >= 60 && attendance {
fmt.Println("通过")
}

常见错误

// ❌ 错误:条件必须是布尔值
if x := 10; x { // 编译错误
fmt.Println(x)
}

// ✅ 正确
if x := 10; x > 0 {
fmt.Println(x)
}

switch 语句

基本语法

switch 变量 {
case1:
// 匹配值1时执行
case2:
// 匹配值2时执行
default:
// 都不匹配时执行
}

示例

day := 3

switch day {
case 1:
fmt.Println("星期一")
case 2:
fmt.Println("星期二")
case 3:
fmt.Println("星期三")
case 4:
fmt.Println("星期四")
case 5:
fmt.Println("星期五")
case 6, 7: // 多个值
fmt.Println("周末")
default:
fmt.Println("无效的日期")
}

多条件匹配

grade := 'B'

switch grade {
case 'A', 'a':
fmt.Println("优秀")
case 'B', 'b':
fmt.Println("良好")
case 'C', 'c':
fmt.Println("及格")
default:
fmt.Println("不及格")
}

switch 不带变量

age := 20

switch {
case age < 18:
fmt.Println("未成年")
case age >= 18 && age < 60:
fmt.Println("成年人")
default:
fmt.Println("老年人")
}

fallthrough

Go 的 switch 语句默认不会 fallthrough,如果需要继续执行下一个 case,使用 fallthrough:

score := 75

switch {
case score >= 90:
fmt.Println("优秀")
fallthrough
case score >= 80:
fmt.Println("良好")
fallthrough
case score >= 60:
fmt.Println("及格")
default:
fmt.Println("不及格")
}

// 输出:
// 及格
注意

fallthrough 会无条件执行下一个 case,建议谨慎使用。

简短语句

switch day := getDay(); day {
case 1:
fmt.Println("星期一")
case 2:
fmt.Println("星期二")
default:
fmt.Println("其他")
}

for 循环

Go 只有一种循环结构 for,但可以用多种方式使用。

基本语法

for 初始化; 条件; 后置语句 {
// 循环体
}

标准 for 循环

// 打印 1 到 5
for i := 1; i <= 5; i++ {
fmt.Println(i)
}

省略初始化

i := 1
for ; i <= 5; i++ {
fmt.Println(i)
}

省略条件(死循环)

for {
fmt.Println("无限循环")
if condition {
break
}
}

省略所有(while 风格)

i := 1
for i <= 5 {
fmt.Println(i)
i++
}

break 和 continue

// break:跳出循环
for i := 1; i <= 10; i++ {
if i == 6 {
break // 打印 1-5
}
fmt.Println(i)
}

// continue:跳过本次循环
for i := 1; i <= 5; i++ {
if i == 3 {
continue // 跳过 3
}
fmt.Println(i)
}
// 输出: 1, 2, 4, 5

嵌套循环

// 打印九九乘法表
for i := 1; i <= 9; i++ {
for j := 1; j <= i; j++ {
fmt.Printf("%d*%d=%d\t", j, i, i*j)
}
fmt.Println()
}

标签和跳转

outer:
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
if i == 1 && j == 1 {
break outer // 跳出外层循环
}
fmt.Printf("(%d,%d)\n", i, j)
}
}

range 循环

range 用于遍历数组、切片、映射、字符串和通道。

遍历数组/切片

// 遍历数组
nums := []int{1, 2, 3, 4, 5}

for index, value := range nums {
fmt.Printf("索引: %d, 值: %d\n", index, value)
}

// 只需要值
for _, value := range nums {
fmt.Println(value)
}

// 只需要索引
for index := range nums {
fmt.Println(index)
}

// 省略索引和值
for range nums {
fmt.Println("迭代一次")
}

遍历字符串

str := "Hello, 世界"

for index, rune := range str {
fmt.Printf("索引: %d, 字符: %c, Unicode: %U\n", index, rune, rune)
}

// 输出:
// 索引: 0, 字符: H, Unicode: U+0048
// 索引: 1, 字符: e, Unicode: U+0065
// ...
// 索引: 7, 字符: 世, Unicode: U+4E16
// 索引: 10, 字符: 界, Unicode: U+754C

遍历映射

ages := map[string]int{
"张三": 25,
"李四": 30,
"王五": 28,
}

for name, age := range ages {
fmt.Printf("%s: %d岁\n", name, age)
}

// 只遍历键
for name := range ages {
fmt.Println(name)
}

// 只遍历值
for _, age := range ages {
fmt.Println(age)
}

// 遍历顺序随机

遍历通道

ch := make(chan int, 5)
for i := 0; i < 5; i++ {
ch <- i
}
close(ch)

for v := range ch {
fmt.Println(v)
}

跳转语句

goto

goto 可以跳转到同一个函数内的标签:

func main() {
i := 0

Loop:
for i < 10 {
if i == 5 {
i++
goto Loop // 跳转到 Loop 标签
}
fmt.Println(i)
i++
}
}
警告

过度使用 goto 会使代码难以理解和维护,建议尽量避免。

循环中的错误处理

// 使用闭包封装
func main() {
result, err := process()
if err != nil {
fmt.Println("错误:", err)
return
}
fmt.Println("结果:", result)
}

func process() (int, error) {
for i := 0; i < 10; i++ {
if i == 5 {
return i, nil
}
}
return 0, errors.New("未找到")
}

常见模式

遍历查找

nums := []int{1, 3, 5, 7, 9}
target := 5
found := false

for _, num := range nums {
if num == target {
found = true
break
}
}

if found {
fmt.Println("找到目标")
} else {
fmt.Println("未找到")
}

计数

count := 0
for _, v := range []int{1, 2, 3, 4, 5} {
if v > 3 {
count++
}
}
fmt.Println("大于3的数量:", count)

过滤

nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
var evens []int

for _, n := range nums {
if n%2 == 0 {
evens = append(evens, n)
}
}
fmt.Println("偶数:", evens)

映射转换

nums := []int{1, 2, 3, 4, 5}
var doubled []int

for _, n := range nums {
doubled = append(doubled, n*2)
}
fmt.Println("翻倍:", doubled)

小结

  1. if 语句:条件判断,支持简短语句
  2. switch 语句:多条件分支,不需要 break
  3. for 循环:Go 只有 for 循环,支持多种形式
  4. range 循环:遍历数组、切片、映射、字符串、通道
  5. break 和 continue:控制循环流程
  6. goto:跳转语句(慎用)

练习

  1. 打印 1-100 中所有偶数
  2. 计算 1+2+3+...+100 的和
  3. 使用 switch 判断成绩等级
  4. 找出数组中的最大值和最小值
  5. 使用 range 遍历并打印 map 的键值对
  6. 实现一个简单的猜数字游戏