golang日常开发系列之一--defer的那些坑"

简介: golang日常开发系列之一--defer的那些坑"

最近集中开发了一波golang, 因此打算开启一个坑,就叫golang日常开发系列,用于总结这段时间内遇到的各种奇奇怪怪的关于golang开发的一些问题, 后续如果有新奇的问题也会加以补充.


废话不多说,我们直接进入系列之一,看看defer使用过程中有哪些坑,如何解决?



一、所谓的"坑"


func logErr(err error) {
 fmt.Println(err)
}
func main() error {
 var err error
    defer logErr(err)
 err = fmt.Errorf("error")
 return err
}


上面的代码试图在main函数退出的时候,将err变量打印出来。你认为会输出什么呢?nil 还是 error ? 一般我们会想err再return之前已经从nil变成非nil值,所以执行defer的时候应该会打印error吧?很遗憾,结果并不是这样,代码的输出是nil



二、原因


为什么会出现与我们预期不同的结果呢?因为logErr是一样函数,注册defer LogErr(err)的时候,会将err当前值nil传递给LogErr。当函数退出执行defer代码的时候,打印的便是传入的形参值nil.


之所以我们觉得不符合预期,还是因为对golang defer和函数的运行机制理解不到位




三、解决


3.1 指针法


明白了原因,解决方法就出来了。logErr不是传值吗,既然传err不奏效(因为err后续会重新被赋值),我传指向err的指针行不行,这样不管err值如何变化,我通过指针都能获取最新的err值。


func logErr(err *error) {
    fmt.Println(*err)
}
func main() error {
 var err error
    defer logErr(&err)
 err = fmt.Errorf("error")
 return err
}


以上代码输出结果为error



3.2 闭包法


我们知道使用闭包时,闭包会引用外部的变量, 根据闭包的这个特性,也可以实现我们的需求


func logErr(err error) {
    fmt.Println(err)
}
func main() error {
 var err error
    defer func() {
        logErr(err)
    }()
 err = fmt.Errorf("error")
 return err
}


在注册defer时,err的引用会被传入闭包中。不管err后来如何变化,当执行defer时,函数logErr获取到的必然是最新的err值

相关文章
|
1月前
|
JSON 中间件 Go
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
本文详细介绍了如何在Go项目中集成并配置Zap日志库。首先通过`go get -u go.uber.org/zap`命令安装Zap,接着展示了`Logger`与`Sugared Logger`两种日志记录器的基本用法。随后深入探讨了Zap的高级配置,包括如何将日志输出至文件、调整时间格式、记录调用者信息以及日志分割等。最后,文章演示了如何在gin框架中集成Zap,通过自定义中间件实现了日志记录和异常恢复功能。通过这些步骤,读者可以掌握Zap在实际项目中的应用与定制方法
go语言后端开发学习(四) —— 在go项目中使用Zap日志库
|
16天前
|
缓存 弹性计算 API
用 Go 快速开发一个 RESTful API 服务
用 Go 快速开发一个 RESTful API 服务
|
8天前
|
Go API
Golang语言开发注意事项
这篇文章总结了Go语言开发中的注意事项,包括语法细节、注释使用、代码风格、API文档的利用以及如何使用godoc工具来生成文档。
15 2
|
29天前
|
算法 NoSQL 中间件
go语言后端开发学习(六) ——基于雪花算法生成用户ID
本文介绍了分布式ID生成中的Snowflake(雪花)算法。为解决用户ID安全性与唯一性问题,Snowflake算法生成的ID具备全局唯一性、递增性、高可用性和高性能性等特点。64位ID由符号位(固定为0)、41位时间戳、10位标识位(含数据中心与机器ID)及12位序列号组成。面对ID重复风险,可通过预分配、动态或统一分配标识位解决。Go语言实现示例展示了如何使用第三方包`sonyflake`生成ID,确保不同节点产生的ID始终唯一。
go语言后端开发学习(六) ——基于雪花算法生成用户ID
|
30天前
|
JSON 缓存 监控
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
Viper 是一个强大的 Go 语言配置管理库,适用于各类应用,包括 Twelve-Factor Apps。相比仅支持 `.ini` 格式的 `go-ini`,Viper 支持更多配置格式如 JSON、TOML、YAML
go语言后端开发学习(五)——如何在项目中使用Viper来配置环境
|
11天前
|
监控 测试技术 API
|
16天前
|
JSON 编解码 中间件
go-zero代码生成器助你高效开发
go-zero代码生成器助你高效开发
|
16天前
|
Java Go API
我用go-zero开发了第一个线上项目
我用go-zero开发了第一个线上项目
|
27天前
|
监控 Serverless Go
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
Golang 开发函数计算问题之Go 语言中切片扩容时需要拷贝原数组中的数据如何解决
|
27天前
|
Java Serverless Go
Golang 开发函数计算问题之在 Golang 中避免 "concurrent map writes" 异常如何解决
Golang 开发函数计算问题之在 Golang 中避免 "concurrent map writes" 异常如何解决