阐述一下Golang中defer的原理

2024-06-21 18:36

本文主要是介绍阐述一下Golang中defer的原理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基本用法

在Go语言中,defer关键字用于在函数返回前执行一段代码或调用一个清理函数。这对于处理文件关闭、解锁或者返回一些资源到资源池等操作非常有用。

其基本用法如下所示:

package mainimport "fmt"func main() {example()
}func example() {defer fmt.Println("world")fmt.Println("hello")
}

defer fmt.Println("world")语句会在函数example返回之前执行,所以输出的结果是:

在这里插入图片描述

执行顺序

当我们在一个函数内部调用defer关键字,Go实际上会把它后面的函数(通常是一个匿名函数或者清理函数)压入一个栈中。当外部函数准备返回的时候,Go会按照先进先出的(LIFO)的顺序调用并执行这个栈中的所有函数。

比如,如下示例:

package mainimport "fmt"func main() {example()
}func example() {defer fmt.Println("first")defer fmt.Println("second")defer fmt.Println("third")fmt.Println("function body")
}

其输出结果为:在这里插入图片描述

参数计算时机

需要注意的是,defer语句的参数会在defer语句处就计算好,而不是在外部函数返回时才计算。比如如下例子

package mainimport "fmt"func main() {example()
}func example() {i := 0defer fmt.Println(i) i++fmt.Println(i)
}
/*
1
0
*/

实际应用举例

关闭文件
package mainimport ("fmt""io/ioutil""os"
)func readFile(fileName string) (string, error) {file, err := os.Open(fileName)if err != nil {return "", err}defer file.Close() // 确保文件在函数返回前被关闭content, err := ioutil.ReadAll(file)if err != nil {return "", err}return string(content), nil
}func main() {content, err := readFile("example.txt")if err != nil {fmt.Println("Error:", err)return}fmt.Println("File content:", content)
}
解锁互斥锁
package mainimport ("fmt""sync"
)var mtx sync.Mutex
var cnt intconst N int = 10func increment() {mtx.Lock()defer mtx.Unlock()cnt++
}func main() {var wg sync.WaitGroupfor i := 0; i < N; i++ {wg.Add(1)go func() {defer wg.Done()increment()}()}wg.Wait()fmt.Println("Final count: ", cnt)
}
释放网络连接
package mainimport ("fmt""io/ioutil""net/http"
)func fetchURL(url string) (string, error) {resp, err := http.Get(url)if err != nil {return "", err}defer resp.Body.Close() // 确保连接在函数返回前被关闭body, err := ioutil.ReadAll(resp.Body)if err != nil {return "", err}return string(body), nil
}func main() {content, err := fetchURL("http://baidu.com")if err != nil {fmt.Println("Error:", err)return}fmt.Println("URL content:", content)
}

最后给大家推荐一个LinuxC/C++高级架构系统教程的学习资源与课程,可以帮助你有方向、更细致地学习C/C++后端开发,具体内容请见 https://xxetb.xetslk.com/s/1o04uB

这篇关于阐述一下Golang中defer的原理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1082004

相关文章

全面解析Golang 中的 Gorilla CORS 中间件正确用法

《全面解析Golang中的GorillaCORS中间件正确用法》Golang中使用gorilla/mux路由器配合rs/cors中间件库可以优雅地解决这个问题,然而,很多人刚开始使用时会遇到配... 目录如何让 golang 中的 Gorilla CORS 中间件正确工作一、基础依赖二、错误用法(很多人一开

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

在MySQL中实现冷热数据分离的方法及使用场景底层原理解析

《在MySQL中实现冷热数据分离的方法及使用场景底层原理解析》MySQL冷热数据分离通过分表/分区策略、数据归档和索引优化,将频繁访问的热数据与冷数据分开存储,提升查询效率并降低存储成本,适用于高并发... 目录实现冷热数据分离1. 分表策略2. 使用分区表3. 数据归档与迁移在mysql中实现冷热数据分

golang程序打包成脚本部署到Linux系统方式

《golang程序打包成脚本部署到Linux系统方式》Golang程序通过本地编译(设置GOOS为linux生成无后缀二进制文件),上传至Linux服务器后赋权执行,使用nohup命令实现后台运行,完... 目录本地编译golang程序上传Golang二进制文件到linux服务器总结本地编译Golang程序

golang版本升级如何实现

《golang版本升级如何实现》:本文主要介绍golang版本升级如何实现问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录golanwww.chinasem.cng版本升级linux上golang版本升级删除golang旧版本安装golang最新版本总结gola

golang中reflect包的常用方法

《golang中reflect包的常用方法》Go反射reflect包提供类型和值方法,用于获取类型信息、访问字段、调用方法等,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值... 目录reflect包方法总结类型 (Type) 方法值 (Value) 方法reflect包方法总结

从原理到实战深入理解Java 断言assert

《从原理到实战深入理解Java断言assert》本文深入解析Java断言机制,涵盖语法、工作原理、启用方式及与异常的区别,推荐用于开发阶段的条件检查与状态验证,并强调生产环境应使用参数验证工具类替代... 目录深入理解 Java 断言(assert):从原理到实战引言:为什么需要断言?一、断言基础1.1 语

MySQL中的表连接原理分析

《MySQL中的表连接原理分析》:本文主要介绍MySQL中的表连接原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、背景2、环境3、表连接原理【1】驱动表和被驱动表【2】内连接【3】外连接【4编程】嵌套循环连接【5】join buffer4、总结1、背景

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

Golang如何用gorm实现分页的功能

《Golang如何用gorm实现分页的功能》:本文主要介绍Golang如何用gorm实现分页的功能方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景go库下载初始化数据【1】建表【2】插入数据【3】查看数据4、代码示例【1】gorm结构体定义【2】分页结构体