golang defer语句

  • 时间:2025-11-19 19:45 作者: 来源: 阅读:0
  • 扫一扫,手机访问
摘要:在 Go 语言中,defer 语句是一个超级有用且常用的特性,它允许推迟一个函数调用的执行,直到包含 defer 语句的函数即将返回时才执行。defer 常用于资源清理,如关闭文件、释放锁、关闭网络连接等。1. 基本语法defer functionCall()defer 后面跟一个函数调用(或方法调用),该调用会被推迟执行。2. 执行时机defer 的函数调用会在当前函数返回之前执行。无论函数是正

在 Go 语言中,defer 语句是一个超级有用且常用的特性,它允许推迟一个函数调用的执行,直到包含 defer 语句的函数即将返回时才执行。defer 常用于资源清理,如关闭文件、释放锁、关闭网络连接等。

1. 基本语法

defer functionCall()

defer 后面跟一个函数调用(或方法调用),该调用会被推迟执行。

2. 执行时机

  • defer 的函数调用会在当前函数返回之前执行。
  • 无论函数是正常返回还是发生 panic,defer 都会被执行。
package main

import "fmt"

func main() {
    defer fmt.Println("deferred print")
    fmt.Println("normal print")
    return
    // 输出:
    // normal print
    // deferred print
}

3. 延迟求值(参数求值时机)

defer 语句在执行时会立即计算函数的参数,但函数本身被推迟执行。

package main

import "fmt"

func main() {
    i := 10
    defer fmt.Println(i) // 输出 10,不是 20
    i = 20
    fmt.Println("hello")
}

// 输出:
// hello
// 10

注意:fmt.Println(i) 中的 i 在 defer 被执行时就被求值为 10,即使后面 i 被修改为 20。

4. LIFO(后进先出)顺序执行

如果有多个 defer,它们会以的方式执行:后声明的先执行。

package main

import "fmt"

func main() {
    defer fmt.Println(1)
    defer fmt.Println(2)
    defer fmt.Println(3)
}

// 输出:
// 3
// 2
// 1

5. 常见用途

✅ 关闭文件

package main

import (
    "log"
    "os"
)

func main() {
    file, err := os.Open("data.txt")
    if err != nil {
       log.Fatal(err)
    }
    defer func(file *os.File) {
       err := file.Close()
       if err != nil {
          log.Fatal(err)
       }
    }(file) // 确保函数结束时关闭文件
}

✅ 释放锁

mu.Lock()
defer mu.Unlock()
// 临界区操作

✅ 记录函数执行过程

package main

import (
    "fmt"
)

func main() {
    b()
}

func trace(s string) string {
    fmt.Println("进入:", s)
    return s
}
func un(s string) {
    fmt.Println("退出:", s)
}
func a() {
    defer un(trace("a")) // trace("a") 立即执行,返回 "a",un("a") 推迟到后面
    fmt.Println("in a")
}
func b() {
    defer un(trace("b"))
    fmt.Println("in b")
    a()
}
输出:
进入: b
in b
进入: a
in a
退出: a
退出: b

6. 与 return 的交互

defer 可以修改命名返回值(named return values)。

func c() (i int) {
    defer func() {
       i++ // 修改命名返回值
    }()
    i = 1
    return i // 返回的是 i,此时 i 已经被 defer 改为 2
}

7. 注意事项

  • defer 不会阻止 panic,但可以在 panic 后执行清理。
  • defer 函数在 return 之后、函数真正退出之前执行。
  • 在循环中使用 defer 要小心,可能会导致性能问题或资源延迟释放。
// ❌ 错误示例:在循环中 defer 文件关闭
for _, file := range files {
f, _ := os.Open(file)
defer f.Close() // 所有文件都在函数结束时才关闭
}

应改为:

// ✅ 正确做法:在函数内处理
for _, file := range files {
func() {
f, _ := os.Open(file)
defer f.Close()
// 处理文件
}()
}

特性

说明

执行时机

函数 return 前

参数求值

defer 时立即求值

执行顺序

LIFO(后进先出)

用途

资源清理、错误处理、日志记录等

注意

避免在循环中滥用

  • 全部评论(0)
手机二维码手机访问领取大礼包
返回顶部