defer关键字:延迟调用机制-《Go语言实战指南》

defer 是 Go 语言中用于延迟执行函数调用的关键字。它广泛用于资源释放、异常捕获、日志记录等场景,是构建健壮代码的利器。


一、基本语法

复制代码
defer 函数调用
  • • defer 语句会推迟函数的执行,直到包含它的函数执行完毕。
  • • 多个 defer 会以栈的方式后进先出(LIFO)执行。
示例:
复制代码
func test() {
    defer fmt.Println("A")
    defer fmt.Println("B")
    fmt.Println("C")
}

test()
// 输出:
// C
// B
// A

二、常见应用场景

1. 资源释放
复制代码
file, err := os.Open("test.txt")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

打开文件后,使用 defer 确保最终关闭文件,即使中途发生错误也能安全释放资源。


2. 锁的释放
复制代码
mu.Lock()
defer mu.Unlock()

3. 捕获异常

结合 recover() 使用,优雅处理 panic:

复制代码
func safe() {
    defer func() {
        if r := recover(); r != nil {
            fmt.Println("捕获异常:", r)
        }
    }()

    panic("something went wrong")
}

safe()
// 输出:捕获异常: something went wrong

三、参数的求值时机

虽然函数调用被延迟,但参数会立即计算。

复制代码
func test(x int) {
    defer fmt.Println("defer:", x)
    x++
    fmt.Println("normal:", x)
}

test(10)
// 输出:
// normal: 11
// defer: 10

四、defer 的性能影响

  • • defer 虽然非常实用,但在高性能敏感代码中频繁使用 defer 可能造成微小开销。
  • • Go 1.14 起,defer 性能有显著优化。

五、多个 defer 的执行顺序

复制代码
func f() {
    for i := 1; i <= 3; i++ {
        defer fmt.Println("defer", i)
    }
}
f()
// 输出:
// defer 3
// defer 2
// defer 1

六、小技巧:修改返回值

defer 可用于修改命名返回值,用于函数退出前调整返回数据。

复制代码
func demo() (result int) {
    defer func() {
        result += 100
    }()
    return 1
}

fmt.Println(demo()) // 输出 101

七、小结

特性 说明
延迟执行 在函数返回前执行,可用于清理资源
栈顺序 多个 defer 后进先出执行
参数时机 参数立即求值,函数调用延迟执行
常见用途 文件关闭、解锁、恢复 panic 等
返回值控制 可用于修改命名返回值

defer 简洁强大,是写出安全、可维护 Go 代码的重要利器。

相关推荐
程序猿DD4 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
余槐i7 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8267 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
死磕音视频8 小时前
让小模型做选择题:限定候选项并读取 logits 概率的入门实践(附 Python 代码)
开发语言·python·大模型·文本分类·transformers
凤山老林8 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne9 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF9 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
pride.li10 小时前
第03章 Python 教程-基础语法:注释与变量
服务器·前端·后端·python·算法·计算机视觉
顽疲10 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog10 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友