defer在Go中用于延迟执行函数,确保资源如文件、锁等被正确释放。它按后进先出顺序执行,参数在defer语句时即求值,广泛应用于文件操作、并发控制及临时资源清理,提升代码健壮性与可维护性。

defer
defer
panic
return
defer
defer
defer
defer
defer
一个很关键的点是,被
defer
defer
defer
让我们看一个最基础的例子:
立即学习“go语言免费学习笔记(深入)”;
package main
import "fmt"
func exampleDefer() {
fmt.Println("函数开始执行")
defer fmt.Println("这是第一个 defer")
defer fmt.Println("这是第二个 defer")
defer func() {
fmt.Println("这是一个匿名函数 defer")
}()
fmt.Println("函数执行中...")
// 假设这里有一些复杂的逻辑,可能会提前返回或者发生panic
// 但无论如何,上面的 defer 都会被执行
fmt.Println("函数即将返回")
}
func main() {
exampleDefer()
// 输出顺序会是:
// 函数开始执行
// 函数执行中...
// 函数即将返回
// 这是一个匿名函数 defer
// 这是第二个 defer
// 这是第一个 defer
}从输出就能清晰地看到LIFO的执行顺序。这让我觉得
defer
在Go语言中处理文件,最常见也最容易出错的就是忘记关闭文件句柄,导致资源泄露。
defer
defer
想象一下,如果你不使用
defer
return
file.Close()
defer
package main
import (
"fmt"
"os"
)
func readFile(filename string) ([]byte, error) {
file, err := os.Open(filename)
if err != nil {
return nil, fmt.Errorf("无法打开文件: %w", err)
}
// 关键在这里!无论函数后续如何,文件都会被关闭。
// 即使在读取过程中发生错误,defer 也能保证 file.Close() 被调用。
defer func() {
if closeErr := file.Close(); closeErr != nil {
// 在实际应用中,这里可能需要记录日志,因为 file.Close() 失败也是个问题
fmt.Printf("关闭文件 %s 时发生错误: %v\n", filename, closeErr)
}
}()
// 假设文件内容不大,一次性读取
data := make([]byte, 1024)
n, err := file.Read(data)
if err != nil {
return nil, fmt.Errorf("读取文件 %s 时发生错误: %w", filename, err)
}
return data[:n], nil
}
func main() {
// 创建一个临时文件用于测试
tempFile := "test.txt"
err := os.WriteFile(tempFile, []byte("Hello, defer in Go!"), 0644)
if err != nil {
fmt.Println("创建临时文件失败:", err)
return
}
defer os.Remove(tempFile) // 用 defer 确保测试文件在 main 函数结束时被删除
content, err := readFile(tempFile)
if err != nil {
fmt.Println("读取文件失败:", err)
return
}
fmt.Printf("文件内容: %s\n", string(content))
// 尝试读取一个不存在的文件
_, err = readFile("non_existent_file.txt")
if err != nil {
fmt.Println("读取不存在文件时的错误:", err)
}
}你看,在
readFile
defer file.Close()
os.Open
defer
file.Close()
在并发编程中,锁(如
sync.Mutex
defer
当我第一次接触到
defer
defer mu.Unlock()
package main
import (
"fmt"
"sync"
"time"
)
type Counter struct {
mu sync.Mutex
value int
}
func (c *Counter) Increment() {
c.mu.Lock()
// 立即 defer 解锁,确保无论后续逻辑如何,锁都会被释放
defer c.mu.Unlock()
// 模拟一些耗时操作
time.Sleep(10 * time.Millisecond)
c.value++
}
func (c *Counter) GetValue() int {
c.mu.Lock()
defer c.mu.Unlock() // 读取也需要加锁以保证数据一致性
return c.value
}
func main() {
counter := Counter{}
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
counter.Increment()
}()
}
wg.Wait()
fmt.Printf("最终计数器值: %d\n", counter.GetValue())
}在这个计数器示例中,
counter.mu.Lock()
defer c.mu.Unlock()
Increment
panic
c.mu.Unlock()
defer
一个我经常会用到的场景是,当一个函数需要创建一些临时资源(比如临时目录、临时文件),并在函数结束时无论成功失败都需要清理掉它们。
defer
package main
import (
"fmt"
"os"
"path/filepath"
"time"
)
// createAndProcessTempDir 演示如何使用 defer 清理临时目录
func createAndProcessTempDir() error {
// 创建一个带有时间戳的临时目录
tempDir := filepath.Join(os.TempDir(), fmt.Sprintf("my_app_temp_%d", time.Now().UnixNano()))
if err := os.MkdirAll(tempDir, 0755); err != nil {
return fmt.Errorf("创建临时目录失败: %w", err)
}
fmt.Printf("临时目录已创建: %s\n", tempDir)
// 确保函数退出时删除临时目录,无论成功失败
defer func() {
fmt.Printf("清理临时目录: %s\n", tempDir)
if err := os.RemoveAll(tempDir); err != nil {
fmt.Printf("删除临时目录 %s 失败: %v\n", tempDir, err)
}
}()
// 在临时目录中创建一些文件
tempFile := filepath.Join(tempDir, "data.txt")
if err := os.WriteFile(tempFile, []byte("Hello from temp file!"), 0644); err != nil {
return fmt.Errorf("写入临时文件失败: %w", err)
}
fmt.Printf("临时文件已创建: %s\n", tempFile)
// 模拟一些处理逻辑,可能成功,也可能失败
// 假设这里我们模拟一个错误,看看 defer 是否依然有效
if time.Now().Second()%2 == 0 { // 随机模拟错误
return fmt.Errorf("模拟处理逻辑失败,但临时目录会清理")
}
fmt.Println("临时目录处理完成。")
return nil
}
func main() {
fmt.Println("开始执行主函数...")
if err := createAndProcessTempDir(); err != nil {
fmt.Println("createAndProcessTempDir 错误:", err)
}
fmt.Println("主函数执行完毕。")
// 检查临时目录是否真的被删除了
// time.Sleep(100 * time.Millisecond) // 给文件系统一点时间
// 如果上面有错误,这里会看到清理日志,但不会再次创建或删除
}在这个例子里,
defer os.RemoveAll(tempDir)
createAndProcessTempDir
从性能角度看,
defer
defer
defer
以上就是Golangdefer延迟调用使用场景与示例的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号