func CopyFile(dstName, srcName string) (written int64, err error) {
src, err := os.Open(srcName)
if err != nil {
return
}
defer src.Close()
dst, err := os.Create(dstName)
if err != nil {
return
}
defer dst.Close()
return io.Copy(dst, src)
}
//我在网上看到一位大神讲解defer执行的代码,我理解假如第一个err不等于nil,下边的defer src.Close()不会执行,因为没在第一个return之前定义
golang os.open defer调用的问题
- 写回答
- 好问题 0 提建议
- 关注问题
- 邀请回答
-
4条回答 默认 最新
关注让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。
如果答案让您满意,请采纳、点赞、关注,非常感谢!
.
每日一句正能量,让它带给您好心情:阳光总在风雨后,请相信有彩虹。
.根据你的代码和描述,我来详细解释一下 Go 语言中
defer的执行机制。代码分析
func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return // 如果这里返回,下面的 defer src.Close() 不会执行 } defer src.Close() // 这行代码只有在成功打开文件后才会注册 dst, err := os.Create(dstName) if err != nil { return // 如果这里返回,下面的 defer dst.Close() 不会执行 } defer dst.Close() // 这行代码只有在成功创建文件后才会注册 return io.Copy(dst, src) }defer 的关键特性
1. defer 的注册时机
defer语句只有在执行到该行代码时才会注册延迟调用。如果代码执行流程在到达defer语句之前就返回了,那么该defer不会被注册。2. 在你的代码中的具体表现
- 情况1:如果
os.Open(srcName)失败 - 执行第一个
return defer src.Close()从未被执行到,因此不会被注册- 函数直接返回错误
- 情况2:如果
os.Open(srcName)成功,但os.Create(dstName)失败 defer src.Close()已注册,会在函数返回时执行defer dst.Close()从未被执行到,因此不会被注册- 函数返回时只关闭源文件
- 情况3:两个操作都成功
- 两个
defer都注册成功 - 函数返回时按 LIFO(后进先出)顺序执行:
- 先执行
dst.Close() - 再执行
src.Close()
最佳实践建议
为了代码更清晰,可以考虑以下改进:
func CopyFile(dstName, srcName string) (written int64, err error) { src, err := os.Open(srcName) if err != nil { return 0, fmt.Errorf("open source file: %w", err) } defer src.Close() dst, err := os.Create(dstName) if err != nil { return 0, fmt.Errorf("create destination file: %w", err) } defer dst.Close() written, err = io.Copy(dst, src) if err != nil { return 0, fmt.Errorf("copy file: %w", err) } return written, nil }总结
你的理解是正确的:如果第一个
err != nil导致提前返回,defer src.Close()确实不会执行,因为代码执行流程根本没有到达那一行。这是 Go 语言defer机制的一个重要特性,确保了只有在成功获取资源后才需要负责释放。本回答被题主选为最佳回答 , 对您是否有帮助呢?解决 无用评论 打赏 举报- 情况1:如果