1.3.1 条件语句 #
条件语句是程序控制流程的基础,它允许程序根据不同的条件执行不同的代码分支。Go 语言提供了 if
、switch
等条件语句,语法简洁且功能强大。
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
最佳实践 #
- 早期返回:减少嵌套层次,提高代码可读性
- 条件拆分:将复杂条件拆分为多个函数
- 表驱动:使用数据结构驱动逻辑判断
掌握条件语句的使用是编程的基础技能,为后续学习循环语句和函数奠定了重要基础。
练习题:
- 编写一个成绩等级判断程序,根据分数输出对应等级
- 实现一个简单的菜单系统,根据用户选择执行不同操作
- 创建一个文件权限检查器,判断用户对文件的操作权限
- 编写一个日期格式验证器,支持多种日期格式
- 实现一个简单的状态机,模拟设备的不同工作状态