Go 控制结构

if 语句

基本用法

package main
 
import "fmt"
 
func main() {
    // 基本 if 语句
    x := 10
    if x > 5 {
        fmt.Println("x 大于 5")
    }
    
    // if-else 语句
    if x > 15 {
        fmt.Println("x 大于 15")
    } else {
        fmt.Println("x 不大于 15")
    }
    
    // if-else if-else 语句
    if x > 15 {
        fmt.Println("x 大于 15")
    } else if x > 10 {
        fmt.Println("x 大于 10 但小于等于 15")
    } else {
        fmt.Println("x 小于等于 10")
    }
    
    // if 语句中的短变量声明
    // 变量作用域只在 if 语句块内
    if y := 20; y > 10 {
        fmt.Printf("y (%d) 大于 10\n", y)
    }
    // fmt.Println(y)  // 错误:y 不在作用域内
    
    // 常见用法:错误处理
    result, err := divide(10, 2)
    if err != nil {
        fmt.Printf("错误: %v\n", err)
    } else {
        fmt.Printf("结果: %d\n", result)
    }
    
    // 更简洁的错误处理
    if result, err := divide(10, 0); err != nil {
        fmt.Printf("错误: %v\n", err)
    } else {
        fmt.Printf("结果: %d\n", result)
    }
}
 
func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, fmt.Errorf("除数不能为 0")
    }
    return a / b, nil
}

switch 语句

基本用法

package main
 
import "fmt"
 
func main() {
    // 基本 switch 语句
    day := 3
    switch day {
    case 1:
        fmt.Println("星期一")
    case 2:
        fmt.Println("星期二")
    case 3:
        fmt.Println("星期三")
    default:
        fmt.Println("其他")
    }
    
    // switch 语句中的短变量声明
    switch num := 5; num {
    case 1, 2, 3:
        fmt.Println("小数字")
    case 4, 5, 6:
        fmt.Println("中等数字")
    default:
        fmt.Println("大数字")
    }
    
    // 无表达式的 switch(相当于 if-else if-else)
    score := 85
    switch {
    case score >= 90:
        fmt.Println("优秀")
    case score >= 80:
        fmt.Println("良好")
    case score >= 60:
        fmt.Println("及格")
    default:
        fmt.Println("不及格")
    }
    
    // fallthrough:继续执行下一个 case
    x := 1
    switch x {
    case 1:
        fmt.Println("1")
        fallthrough  // 继续执行 case 2
    case 2:
        fmt.Println("2")
    case 3:
        fmt.Println("3")
    }
    // 输出:
    // 1
    // 2
    
    // 类型 switch(用于接口类型)
    var i interface{} = "hello"
    switch v := i.(type) {
    case int:
        fmt.Printf("整数: %d\n", v)
    case string:
        fmt.Printf("字符串: %s\n", v)
    case bool:
        fmt.Printf("布尔: %t\n", v)
    default:
        fmt.Printf("未知类型: %T\n", v)
    }
}

for 循环

基本用法

package main
 
import "fmt"
 
func main() {
    // 基本 for 循环(类似 C 语言)
    for i := 0; i < 5; i++ {
        fmt.Printf("%d ", i)
    }
    fmt.Println()  // 输出:0 1 2 3 4
    
    // 只有条件的 for 循环(类似 while)
    i := 0
    for i < 5 {
        fmt.Printf("%d ", i)
        i++
    }
    fmt.Println()  // 输出:0 1 2 3 4
    
    // 无限循环
    j := 0
    for {
        if j >= 5 {
            break  // 跳出循环
        }
        fmt.Printf("%d ", j)
        j++
    }
    fmt.Println()  // 输出:0 1 2 3 4
    
    // continue:跳过本次循环
    for i := 0; i < 5; i++ {
        if i == 2 {
            continue  // 跳过 i == 2 的情况
        }
        fmt.Printf("%d ", i)
    }
    fmt.Println()  // 输出:0 1 3 4
    
    // 嵌套循环和标签
outer:
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            if i == 1 && j == 1 {
                break outer  // 跳出外层循环
            }
            fmt.Printf("(%d,%d) ", i, j)
        }
    }
    fmt.Println()  // 输出:(0,0) (0,1) (0,2) (1,0)
}

range 循环

package main
 
import "fmt"
 
func main() {
    // 遍历数组/切片
    arr := []int{10, 20, 30, 40, 50}
    for index, value := range arr {
        fmt.Printf("索引 %d: 值 %d\n", index, value)
    }
    
    // 只要索引
    for index := range arr {
        fmt.Printf("索引: %d\n", index)
    }
    
    // 只要值(使用 _ 忽略索引)
    for _, value := range arr {
        fmt.Printf("值: %d\n", value)
    }
    
    // 遍历字符串(按 rune)
    str := "Hello"
    for index, char := range str {
        fmt.Printf("索引 %d: 字符 %c (Unicode: %d)\n", index, char, char)
    }
    
    // 遍历 map
    m := map[string]int{
        "apple":  5,
        "banana": 3,
        "orange": 2,
    }
    for key, value := range m {
        fmt.Printf("键: %s, 值: %d\n", key, value)
    }
    
    // 遍历 channel(需要先关闭 channel)
    ch := make(chan int, 3)
    ch <- 1
    ch <- 2
    ch <- 3
    close(ch)  // 关闭 channel
    
    for value := range ch {
        fmt.Printf("从 channel 接收: %d\n", value)
    }
}

defer 语句

package main
 
import "fmt"
 
func main() {
    // defer 语句:延迟执行,在函数返回前执行
    defer fmt.Println("延迟执行 1")
    defer fmt.Println("延迟执行 2")
    defer fmt.Println("延迟执行 3")
    
    fmt.Println("正常执行")
    
    // 输出:
    // 正常执行
    // 延迟执行 3
    // 延迟执行 2
    // 延迟执行 1
    // 注意:defer 执行顺序是 LIFO(后进先出)
    
    // defer 的常见用途:资源清理
    deferExample()
}
 
func deferExample() {
    fmt.Println("开始")
    
    // 模拟打开文件
    fmt.Println("打开文件")
    defer fmt.Println("关闭文件")  // 确保文件被关闭
    
    // 模拟处理文件
    fmt.Println("处理文件")
    
    // 函数返回时,defer 语句会执行
    // 输出:
    // 开始
    // 打开文件
    // 处理文件
    // 关闭文件
}
 
// defer 捕获返回值
func deferReturn() (result int) {
    defer func() {
        result++  // 修改返回值
    }()
    return 0  // 实际返回 1
}
 
// defer 与 panic/recover
func deferPanic() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Printf("捕获到 panic: %v\n", r)
        }
    }()
    
    panic("发生错误")
    fmt.Println("这行不会执行")
}

goto 语句

package main
 
import "fmt"
 
func main() {
    // goto 语句:跳转到标签
    i := 0
    
loop:  // 标签
    if i < 5 {
        fmt.Printf("%d ", i)
        i++
        goto loop  // 跳转到 loop 标签
    }
    fmt.Println()  // 输出:0 1 2 3 4
    
    // goto 的常见用途:错误处理
    err := process()
    if err != nil {
        goto cleanup
    }
    
    fmt.Println("处理成功")
    
cleanup:
    fmt.Println("清理资源")
}
 
func process() error {
    // 模拟处理
    return nil
}

break 和 continue

package main
 
import "fmt"
 
func main() {
    // break:跳出循环
    for i := 0; i < 10; i++ {
        if i == 5 {
            break  // 跳出循环
        }
        fmt.Printf("%d ", i)
    }
    fmt.Println()  // 输出:0 1 2 3 4
    
    // continue:跳过本次循环
    for i := 0; i < 10; i++ {
        if i%2 == 0 {
            continue  // 跳过偶数
        }
        fmt.Printf("%d ", i)
    }
    fmt.Println()  // 输出:1 3 5 7 9
    
    // 带标签的 break
outer:
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            if i == 1 && j == 1 {
                break outer  // 跳出外层循环
            }
            fmt.Printf("(%d,%d) ", i, j)
        }
    }
    fmt.Println()
    
    // 带标签的 continue
outer2:
    for i := 0; i < 3; i++ {
        for j := 0; j < 3; j++ {
            if i == 1 && j == 1 {
                continue outer2  // 继续外层循环的下一次迭代
            }
            fmt.Printf("(%d,%d) ", i, j)
        }
    }
    fmt.Println()
}

控制结构最佳实践

package main
 
import (
    "fmt"
    "os"
)
 
func main() {
    // 1. 错误处理模式
    file, err := os.Open("file.txt")
    if err != nil {
        fmt.Printf("打开文件失败: %v\n", err)
        return
    }
    defer file.Close()  // 确保文件被关闭
    
    // 2. 早期返回模式(减少嵌套)
    // 不好的写法(深层嵌套)
    func badStyle() {
        if condition1 {
            if condition2 {
                if condition3 {
                    // 处理逻辑
                }
            }
        }
    }
    
    // 好的写法(早期返回)
    func goodStyle() {
        if !condition1 {
            return
        }
        if !condition2 {
            return
        }
        if !condition3 {
            return
        }
        // 处理逻辑
    }
    
    // 3. switch 用于多值判断
    value := 5
    switch value {
    case 1, 2, 3:
        fmt.Println("小")
    case 4, 5, 6:
        fmt.Println("中")
    default:
        fmt.Println("大")
    }
    
    // 4. range 遍历(推荐)
    arr := []int{1, 2, 3, 4, 5}
    for _, v := range arr {
        fmt.Println(v)
    }
    
    // 5. defer 用于资源清理
    func resourceCleanup() {
        // 打开资源
        resource := acquireResource()
        defer releaseResource(resource)  // 确保释放
        
        // 使用资源
        useResource(resource)
    }
}
 
func acquireResource() interface{} {
    return "resource"
}
 
func releaseResource(r interface{}) {
    fmt.Println("释放资源")
}
 
func useResource(r interface{}) {
    fmt.Println("使用资源")
}

总结

Go 的控制结构特点:

  1. if 语句:支持短变量声明,常用于错误处理
  2. switch 语句:功能强大,支持类型判断
  3. for 循环:只有一种循环语句,但用法灵活
  4. range 循环:遍历数组、切片、map、字符串、channel
  5. defer 语句:延迟执行,常用于资源清理
  6. break/continue:支持标签,可以控制外层循环

掌握这些控制结构后,就可以编写复杂的程序逻辑了!


go 控制结构 if switch for defer