1.3.1 条件语句

1.3.1 条件语句 #

条件语句是程序控制流程的基础,它允许程序根据不同的条件执行不同的代码分支。Go 语言提供了 ifswitch 等条件语句,语法简洁且功能强大。

if 语句 #

1. 基本 if 语句 #

Go 语言的 if 语句不需要括号包围条件表达式,但必须使用大括号:

package main

import "fmt"

func main() {
    age := 18

    // 基本 if 语句
    if age >= 18 {
        fmt.Println("你已经成年了")
    }

    // if-else 语句
    score := 85
    if score >= 90 {
        fmt.Println("优秀")
    } else {
        fmt.Println("良好")
    }

    // if-else if-else 语句
    temperature := 25
    if temperature > 30 {
        fmt.Println("天气很热")
    } else if temperature > 20 {
        fmt.Println("天气温暖")
    } else if temperature > 10 {
        fmt.Println("天气凉爽")
    } else {
        fmt.Println("天气寒冷")
    }
}

2. if 语句的初始化 #

Go 语言允许在 if 语句中进行变量初始化:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    // 在 if 语句中初始化变量
    if num := rand.Intn(100); num > 50 {
        fmt.Printf("随机数 %d 大于 50\n", num)
    } else {
        fmt.Printf("随机数 %d 小于等于 50\n", num)
    }
    // 注意:num 变量只在 if 语句块中有效

    // 实际应用示例:错误处理
    if err := validateAge(-5); err != nil {
        fmt.Printf("验证失败: %v\n", err)
    } else {
        fmt.Println("年龄验证通过")
    }

    // 文件操作示例
    if content, err := readConfig("config.txt"); err != nil {
        fmt.Printf("读取配置失败: %v\n", err)
    } else {
        fmt.Printf("配置内容: %s\n", content)
    }
}

func validateAge(age int) error {
    if age < 0 {
        return fmt.Errorf("年龄不能为负数")
    }
    if age > 150 {
        return fmt.Errorf("年龄不能超过150岁")
    }
    return nil
}

func readConfig(filename string) (string, error) {
    // 模拟读取配置文件
    if filename == "" {
        return "", fmt.Errorf("文件名不能为空")
    }
    return "server_port=8080", nil
}

3. 复杂条件判断 #

package main

import "fmt"

func main() {
    // 逻辑运算符组合条件
    username := "admin"
    password := "123456"
    isActive := true

    if username == "admin" && password == "123456" && isActive {
        fmt.Println("登录成功")
    } else {
        fmt.Println("登录失败")
    }

    // 使用函数返回值作为条件
    if isWeekend() {
        fmt.Println("今天是周末,可以休息")
    } else {
        fmt.Println("今天是工作日,要上班")
    }

    // 复杂的业务逻辑判断
    user := User{
        Name:     "张三",
        Age:      25,
        IsVIP:    true,
        Balance:  1000.0,
        IsActive: true,
    }

    if canPurchase(user, 500.0) {
        fmt.Printf("%s 可以购买此商品\n", user.Name)
    } else {
        fmt.Printf("%s 无法购买此商品\n", user.Name)
    }
}

type User struct {
    Name     string
    Age      int
    IsVIP    bool
    Balance  float64
    IsActive bool
}

func isWeekend() bool {
    // 模拟判断是否为周末
    return time.Now().Weekday() == time.Saturday || time.Now().Weekday() == time.Sunday
}

func canPurchase(user User, price float64) bool {
    // 复杂的购买条件判断
    if !user.IsActive {
        return false
    }

    if user.Balance < price {
        return false
    }

    if !user.IsVIP && price > 1000 {
        return false
    }

    if user.Age < 18 {
        return false
    }

    return true
}

switch 语句 #

1. 基本 switch 语句 #

Go 语言的 switch 语句比其他语言更加灵活和强大:

package main

import (
    "fmt"
    "time"
)

func main() {
    // 基本 switch 语句
    day := time.Now().Weekday()

    switch day {
    case time.Monday:
        fmt.Println("星期一,新的一周开始")
    case time.Tuesday:
        fmt.Println("星期二,继续努力")
    case time.Wednesday:
        fmt.Println("星期三,一周过半")
    case time.Thursday:
        fmt.Println("星期四,快到周末了")
    case time.Friday:
        fmt.Println("星期五,TGIF!")
    case time.Saturday, time.Sunday:
        fmt.Println("周末,好好休息")
    default:
        fmt.Println("未知的日期")
    }

    // 数值判断
    score := 85

    switch {
    case score >= 90:
        fmt.Println("等级:A")
    case score >= 80:
        fmt.Println("等级:B")
    case score >= 70:
        fmt.Println("等级:C")
    case score >= 60:
        fmt.Println("等级:D")
    default:
        fmt.Println("等级:F")
    }
}

2. switch 语句的高级用法 #

package main

import (
    "fmt"
    "reflect"
)

func main() {
    // switch 语句中的初始化
    switch hour := time.Now().Hour(); {
    case hour < 6:
        fmt.Println("凌晨时分")
    case hour < 12:
        fmt.Println("上午时光")
    case hour < 18:
        fmt.Println("下午时间")
    default:
        fmt.Println("晚上时刻")
    }

    // 类型判断 switch
    var x interface{} = 42

    switch v := x.(type) {
    case int:
        fmt.Printf("整数: %d\n", v)
    case string:
        fmt.Printf("字符串: %s\n", v)
    case bool:
        fmt.Printf("布尔值: %t\n", v)
    case float64:
        fmt.Printf("浮点数: %.2f\n", v)
    default:
        fmt.Printf("未知类型: %T\n", v)
    }

    // 使用 fallthrough 关键字
    grade := 'B'

    switch grade {
    case 'A':
        fmt.Println("优秀")
        fallthrough
    case 'B':
        fmt.Println("良好")
        fallthrough
    case 'C':
        fmt.Println("及格")
    case 'D':
        fmt.Println("不及格")
    default:
        fmt.Println("无效等级")
    }
}

3. 实际应用示例 #

package main

import (
    "fmt"
    "strings"
)

// HTTP 状态码处理
func handleHTTPStatus(statusCode int) string {
    switch statusCode {
    case 200:
        return "OK"
    case 201:
        return "Created"
    case 400:
        return "Bad Request"
    case 401:
        return "Unauthorized"
    case 403:
        return "Forbidden"
    case 404:
        return "Not Found"
    case 500:
        return "Internal Server Error"
    default:
        return "Unknown Status"
    }
}

// 文件类型判断
func getFileType(filename string) string {
    ext := strings.ToLower(filename[strings.LastIndex(filename, ".")+1:])

    switch ext {
    case "jpg", "jpeg", "png", "gif":
        return "图片文件"
    case "mp4", "avi", "mov":
        return "视频文件"
    case "mp3", "wav", "flac":
        return "音频文件"
    case "txt", "md", "doc", "docx":
        return "文档文件"
    case "zip", "rar", "7z":
        return "压缩文件"
    default:
        return "未知文件类型"
    }
}

// 用户权限检查
type UserRole int

const (
    Guest UserRole = iota
    User
    Moderator
    Admin
    SuperAdmin
)

func checkPermission(role UserRole, action string) bool {
    switch role {
    case SuperAdmin:
        return true // 超级管理员拥有所有权限
    case Admin:
        switch action {
        case "read", "write", "delete", "manage_users":
            return true
        default:
            return false
        }
    case Moderator:
        switch action {
        case "read", "write", "moderate":
            return true
        default:
            return false
        }
    case User:
        switch action {
        case "read", "write":
            return true
        default:
            return false
        }
    case Guest:
        return action == "read"
    default:
        return false
    }
}

// 计算器操作
func calculate(a, b float64, operator string) (float64, error) {
    switch operator {
    case "+":
        return a + b, nil
    case "-":
        return a - b, nil
    case "*":
        return a * b, nil
    case "/":
        if b == 0 {
            return 0, fmt.Errorf("除数不能为零")
        }
        return a / b, nil
    case "%":
        if b == 0 {
            return 0, fmt.Errorf("除数不能为零")
        }
        return float64(int(a) % int(b)), nil
    default:
        return 0, fmt.Errorf("不支持的操作符: %s", operator)
    }
}

func main() {
    // 测试 HTTP 状态码处理
    fmt.Println("HTTP 状态码测试:")
    codes := []int{200, 404, 500, 999}
    for _, code := range codes {
        fmt.Printf("状态码 %d: %s\n", code, handleHTTPStatus(code))
    }

    // 测试文件类型判断
    fmt.Println("\n文件类型测试:")
    files := []string{"photo.jpg", "video.mp4", "song.mp3", "document.txt", "archive.zip", "unknown.xyz"}
    for _, file := range files {
        fmt.Printf("%s: %s\n", file, getFileType(file))
    }

    // 测试权限检查
    fmt.Println("\n权限检查测试:")
    roles := []UserRole{Guest, User, Moderator, Admin, SuperAdmin}
    actions := []string{"read", "write", "delete", "manage_users"}

    for _, role := range roles {
        fmt.Printf("角色 %d 的权限:\n", role)
        for _, action := range actions {
            hasPermission := checkPermission(role, action)
            fmt.Printf("  %s: %t\n", action, hasPermission)
        }
        fmt.Println()
    }

    // 测试计算器
    fmt.Println("计算器测试:")
    operations := []struct {
        a, b     float64
        operator string
    }{
        {10, 5, "+"},
        {10, 5, "-"},
        {10, 5, "*"},
        {10, 5, "/"},
        {10, 3, "%"},
        {10, 0, "/"},
        {10, 5, "^"},
    }

    for _, op := range operations {
        result, err := calculate(op.a, op.b, op.operator)
        if err != nil {
            fmt.Printf("%.1f %s %.1f = 错误: %v\n", op.a, op.operator, op.b, err)
        } else {
            fmt.Printf("%.1f %s %.1f = %.2f\n", op.a, op.operator, op.b, result)
        }
    }
}

条件语句的最佳实践 #

1. 早期返回模式 #

package main

import (
    "fmt"
    "errors"
)

// 不好的写法:嵌套过深
func processUserBad(user *User) error {
    if user != nil {
        if user.IsActive {
            if user.Age >= 18 {
                if user.Balance > 0 {
                    // 处理用户逻辑
                    fmt.Println("处理用户成功")
                    return nil
                } else {
                    return errors.New("余额不足")
                }
            } else {
                return errors.New("用户未成年")
            }
        } else {
            return errors.New("用户未激活")
        }
    } else {
        return errors.New("用户为空")
    }
}

// 好的写法:早期返回
func processUserGood(user *User) error {
    if user == nil {
        return errors.New("用户为空")
    }

    if !user.IsActive {
        return errors.New("用户未激活")
    }

    if user.Age < 18 {
        return errors.New("用户未成年")
    }

    if user.Balance <= 0 {
        return errors.New("余额不足")
    }

    // 处理用户逻辑
    fmt.Println("处理用户成功")
    return nil
}

func main() {
    user := &User{
        Name:     "测试用户",
        Age:      20,
        IsVIP:    false,
        Balance:  100.0,
        IsActive: true,
    }

    fmt.Println("测试早期返回模式:")
    if err := processUserGood(user); err != nil {
        fmt.Printf("处理失败: %v\n", err)
    }
}

2. 避免复杂的条件表达式 #

package main

import "fmt"

type Order struct {
    Amount   float64
    IsVIP    bool
    Quantity int
    Category string
}

// 不好的写法:复杂的条件表达式
func calculateDiscountBad(order Order) float64 {
    if (order.IsVIP && order.Amount > 1000 && order.Quantity > 5) ||
       (!order.IsVIP && order.Amount > 2000 && order.Category == "electronics") ||
       (order.Category == "books" && order.Quantity > 10) {
        return 0.2
    } else if (order.IsVIP && order.Amount > 500) ||
              (!order.IsVIP && order.Amount > 1000) {
        return 0.1
    }
    return 0.0
}

// 好的写法:拆分条件判断
func calculateDiscountGood(order Order) float64 {
    if qualifiesForHighDiscount(order) {
        return 0.2
    }

    if qualifiesForLowDiscount(order) {
        return 0.1
    }

    return 0.0
}

func qualifiesForHighDiscount(order Order) bool {
    // VIP 用户高折扣条件
    if order.IsVIP && order.Amount > 1000 && order.Quantity > 5 {
        return true
    }

    // 普通用户电子产品高折扣条件
    if !order.IsVIP && order.Amount > 2000 && order.Category == "electronics" {
        return true
    }

    // 图书类商品高折扣条件
    if order.Category == "books" && order.Quantity > 10 {
        return true
    }

    return false
}

func qualifiesForLowDiscount(order Order) bool {
    if order.IsVIP && order.Amount > 500 {
        return true
    }

    if !order.IsVIP && order.Amount > 1000 {
        return true
    }

    return false
}

func main() {
    orders := []Order{
        {Amount: 1500, IsVIP: true, Quantity: 6, Category: "electronics"},
        {Amount: 2500, IsVIP: false, Quantity: 3, Category: "electronics"},
        {Amount: 800, IsVIP: true, Quantity: 2, Category: "books"},
        {Amount: 300, IsVIP: false, Quantity: 15, Category: "books"},
    }

    fmt.Println("折扣计算测试:")
    for i, order := range orders {
        discount := calculateDiscountGood(order)
        fmt.Printf("订单 %d: 折扣 %.1f%%\n", i+1, discount*100)
    }
}

3. 使用表驱动测试 #

package main

import "fmt"

// 状态机示例
type State int

const (
    StateIdle State = iota
    StateRunning
    StatePaused
    StateStopped
    StateError
)

type Event int

const (
    EventStart Event = iota
    EventPause
    EventResume
    EventStop
    EventError
    EventReset
)

// 状态转换表
var stateTransitions = map[State]map[Event]State{
    StateIdle: {
        EventStart: StateRunning,
        EventError: StateError,
    },
    StateRunning: {
        EventPause: StatePaused,
        EventStop:  StateStopped,
        EventError: StateError,
    },
    StatePaused: {
        EventResume: StateRunning,
        EventStop:   StateStopped,
        EventError:  StateError,
    },
    StateStopped: {
        EventReset: StateIdle,
    },
    StateError: {
        EventReset: StateIdle,
    },
}

func (s State) String() string {
    switch s {
    case StateIdle:
        return "空闲"
    case StateRunning:
        return "运行中"
    case StatePaused:
        return "已暂停"
    case StateStopped:
        return "已停止"
    case StateError:
        return "错误"
    default:
        return "未知状态"
    }
}

func (e Event) String() string {
    switch e {
    case EventStart:
        return "开始"
    case EventPause:
        return "暂停"
    case EventResume:
        return "恢复"
    case EventStop:
        return "停止"
    case EventError:
        return "错误"
    case EventReset:
        return "重置"
    default:
        return "未知事件"
    }
}

type StateMachine struct {
    currentState State
}

func NewStateMachine() *StateMachine {
    return &StateMachine{currentState: StateIdle}
}

func (sm *StateMachine) ProcessEvent(event Event) error {
    transitions, exists := stateTransitions[sm.currentState]
    if !exists {
        return fmt.Errorf("当前状态 %s 没有定义转换", sm.currentState)
    }

    newState, canTransition := transitions[event]
    if !canTransition {
        return fmt.Errorf("状态 %s 不能处理事件 %s", sm.currentState, event)
    }

    fmt.Printf("状态转换: %s -> %s (事件: %s)\n", sm.currentState, newState, event)
    sm.currentState = newState
    return nil
}

func (sm *StateMachine) GetCurrentState() State {
    return sm.currentState
}

func main() {
    sm := NewStateMachine()

    // 测试状态转换
    events := []Event{
        EventStart,
        EventPause,
        EventResume,
        EventStop,
        EventReset,
        EventStart,
        EventError,
        EventReset,
    }

    fmt.Printf("初始状态: %s\n", sm.GetCurrentState())

    for _, event := range events {
        if err := sm.ProcessEvent(event); err != nil {
            fmt.Printf("错误: %v\n", err)
        }
    }

    fmt.Printf("最终状态: %s\n", sm.GetCurrentState())
}

小结 #

本节详细介绍了 Go 语言的条件语句,主要内容包括:

if 语句 #

  • 基本语法:不需要括号,必须使用大括号
  • 初始化语法:可以在条件判断前初始化变量
  • 作用域:初始化的变量只在 if 语句块中有效

switch 语句 #

  • 表达式 switch:根据表达式值进行分支
  • 类型 switch:根据类型进行分支判断
  • 无表达式 switch:相当于 if-else if 链
  • fallthrough:显式执行下一个 case

最佳实践 #

  • 早期返回:减少嵌套层次,提高代码可读性
  • 条件拆分:将复杂条件拆分为多个函数
  • 表驱动:使用数据结构驱动逻辑判断

掌握条件语句的使用是编程的基础技能,为后续学习循环语句和函数奠定了重要基础。


练习题:

  1. 编写一个成绩等级判断程序,根据分数输出对应等级
  2. 实现一个简单的菜单系统,根据用户选择执行不同操作
  3. 创建一个文件权限检查器,判断用户对文件的操作权限
  4. 编写一个日期格式验证器,支持多种日期格式
  5. 实现一个简单的状态机,模拟设备的不同工作状态