当前位置: 首页 > news >正文

【Golang入门】第四章:控制结构——从条件分支到异常处理


【Golang入门】第四章:控制结构——从条件分支到异常处理


1. 本文目标

  • 掌握Go核心控制结构:if-elseswitchfor
  • 深入理解defer执行顺序与底层实现
  • 灵活运用panicrecover实现异常恢复
  • 避免控制结构中的常见陷阱
  • 实战:构建文件资源自动回收系统

2. 基础控制结构回顾

2.1 条件分支(if-else)

特点

  • 条件表达式无需括号
  • 支持变量初始化语句
func checkScore(score int) string {if s := score * 10; s >= 90 {return "A"} else if s >= 80 {  // else必须与if闭合括号同行return "B"} else {return "C"}
}

2.2 多路分支(switch)

进化版switch

  • 支持任意表达式(非仅常量)
  • 默认break,可用fallthrough穿透
func weekDayName(day time.Weekday) string {switch day {case time.Sunday:return "周日"case time.Saturday:return "周六"default:             // 必须处理所有可能性return "工作日"}
}

2.3 循环(for)

唯一循环结构

// 传统三段式
for i := 0; i < 10; i++ {fmt.Print(i)
}// 类while循环
sum := 0
for sum < 100 {sum += 10
}// 无限循环
for {// 需内部break退出
}

3. 深入defer机制

3.1 执行规则

  • LIFO:多个defer按后进先出顺序执行
  • 参数预计算:延迟函数的参数在注册时立即求值

经典案例

func main() {start := time.Now()defer fmt.Println("耗时:", time.Since(start)) // 输出结果错误!start在defer注册时已固定time.Sleep(2 * time.Second)
}

修复方案

defer func() {  // 通过闭包捕获最新值fmt.Println("耗时:", time.Since(start)) 
}()

3.2 底层实现原理

defer在编译时会被转换为:

  1. 创建_defer结构体(存入参数、函数指针)
  2. _defer挂载到Goroutine的链表中
  3. 函数返回前倒序执行链表中的_defer

4. 异常处理:panic与recover

4.1 触发panic

  • 运行时错误自动触发(如数组越界)
  • 手动触发业务流程中断
func process(data []int) {if len(data) == 0 {panic("数据不可为空")  // 抛出异常}// 正常处理...
}

4.2 recover捕获机制

  • 只能在defer函数中生效
  • 需在panic发生前注册recover

正确用法

func safeProcess() {defer func() {if err := recover(); err != nil {fmt.Println("捕获到panic:", err)debug.PrintStack()  // 打印调用栈}}()process([]int{})  // 触发panic
}

5. 实战:文件资源自动回收系统

func ReadFile(filename string) (content string, err error) {file, err := os.Open(filename)if err != nil {return "", err}// 确保文件关闭(即使中间发生panic)defer func() {if closeErr := file.Close(); closeErr != nil {err = fmt.Errorf("文件关闭失败: %v", closeErr)}}()data, err := io.ReadAll(file)if err != nil {panic("读取文件异常")  // 触发panic}return string(data), nil
}func main() {defer func() {if r := recover(); r != nil {fmt.Println("系统恢复:", r)}}()content, err := ReadFile("test.txt")if err != nil {fmt.Println("错误:", err)return}fmt.Println(content)
}

6. 高频面试题解析

Q1:defer在循环中注册会怎样?

for i := 0; i < 3; i++ {defer fmt.Print(i)  // 输出 2 1 0
}

所有defer在循环结束后执行,捕获的变量i是最终值(闭包陷阱)

Q2:如何修改defer内的返回值?

通过命名返回值和闭包:

func calc() (result int) {defer func() { result *= 2 }()return 5  // 实际返回10
}

Q3:为什么要在defer中处理recover

recover仅在defer函数内生效,且必须在panic发生前注册才能捕获。


7. 异常处理最佳实践

  1. 慎用panic:只用于不可恢复错误(如配置缺失)
  2. 防御式编程:通过错误码处理预期错误
  3. 资源清理:所有资源操作都通过defer确保释放
  4. 记录上下文:在recover中记录堆栈信息

8. 总结与预告

本章重点

  • defer的执行顺序与参数预计算特性

  • panic/recover的异常恢复机制

  • 控制结构中的闭包陷阱

下节预告: 第五章《函数与闭包》将解密匿名函数、闭包内存泄漏与性能优化!

地址:https://download.csdn.net/download/gou12341234/90924766
(包含异常处理案例、资源回收系统完整实现)


扩展思考
defer遇到os.Exit()会发生什么?为什么?
(提示:os.Exit()会立即终止程序,不执行任何defer

http://www.xdnf.cn/news/685405.html

相关文章:

  • 华为OD机试真题——最小矩阵宽度(宽度最小的子矩阵)(2025A卷:200分)Java/python/JavaScript/C/C++/GO最佳实现
  • craw4ai 抓取实时信息,与 mt4外行行情结合实时交易,基本面来觉得趋势方向,搞一个外汇交易策略
  • FFMPEG推流器讲解
  • CSS选择器:has使用示例
  • MySQL问题:MySQL中主要的锁都有啥?
  • day4 cpp:
  • 杰发科技AC7840——CSE硬件加密模块使用(2)
  • 深入解析 Tomcat 线程管理机制:从设计思想到性能调优
  • 基于正点原子阿波罗F429开发板的LWIP应用(4)——HTTP Server功能
  • 类和对象(中1)
  • 如何加载私钥为 SecKeyRef
  • Word表格怎样插入自动序号或编号
  • AMBA总线家族成员
  • 基于FPGA的DES加解密系统verilog实现,包含testbench和开发板硬件测试
  • c++设计模式-单例模式
  • 数据类型(基本类型下半)day3
  • 智警杯备赛--数据库管理与优化
  • [神经网络]使用olivettiface数据集进行训练并优化,观察对比loss结果
  • LINUX528 重定向
  • Git使用手册保姆级教程
  • 【Python办公】Excel简易透视办公小工具
  • EasyExcel使用导出模版后设置 CellStyle失效问题解决
  • python完成批量复制Excel文件并根据另一个Excel文件中的名称重命名
  • C++之string题目练习
  • jQuery和CSS3卡片列表布局特效
  • tauri2项目打开某个文件夹,类似于mac系统中的 open ./
  • mybatis的mapper对应的xml写法
  • 【技术测评】黑龙江亿林网络「启强 Plus」服务器实测:56 核 32G 配置下的性能表现与应用场景解析
  • BEVDepth- Acquisition of Reliable Depth for Multi-view 3D Object Detection
  • [蓝桥杯C++ 2024 国 B ] 立定跳远(二分)