Go 语言中 defer 使用时有哪些陷阱?

306 天前
 frankphper

大家好,我是 frank ,「 Golang 语言开发栈」公众号作者。

01 介绍

defer 的使用方式是在其后紧跟一个函数调用或方法调用,确保在其所在的函数体返回之前执行其调用的函数或方法。

在 Go 语言中,defer 一般用于资源释放,或使用 defer 调用一个匿名函数,在匿名函数中使用 recover() 处理异常 panic

在使用 defer 时,也很容易遇到陷阱,本文我们介绍使用 defer 时有哪些陷阱。

02 defer 陷阱

defer 语句不可以在 return 语句之后。

示例代码:

func main() {
	name := GetUserName("phper")
	fmt.Printf("name:%s\n", name)
	if name != "gopher" {
		return
	}
	defer fmt.Println("this is a defer call")
}

func GetUserName(name string) string {
	return name
}

输出结果:

name:phper

阅读上面这段代码,我们在 return 语句之后执行 defer 语句,通过输出结果可以发现 defer 语句调用未执行。

虽然 defer 可以在函数体中的任意位置,我们也是需要特别注意使用 defer 的位置是否可以执行。

defer 语句执行匿名函数,参数预处理。

示例代码:

func main() {
	var count int64
	defer func(data int64) {
		fmt.Println("defer:", data)
	}(count + 1)
	count = 100
	fmt.Println("main:", count)
}

输出结果:

main: 100
defer: 1

阅读上面这段代码,首先我们定义一个类型为 int64 的变量 count,然后使用 defer 语句执行一个匿名函数,匿名函数传递参数为 count + 1,最终 main 函数输出 100,defer 执行的匿名函数输出 1

因为在执行 defer 语句时,执行了 count + 1,并先将其存储,等到 defer 所在的函数体 main 执行完,再执行 defer 语句调用的匿名函数的函数体中的代码。

03 总结

本文主要介绍在使用 defer 语句时可能会遇到的陷阱。分别是 defer 语句不可以在 return 语句之后;defer 语句执行的匿名函数,匿名函数的参数会被预先处理。

读者朋友们在使用 Go 语言的 defer 语句时,还遇到过哪些陷阱?

2593 次点击
所在节点    Go 编程语言
9 条回复
seers
306 天前
闭包就闭包,又来个预处理
dyllen
306 天前
package main

import "fmt"

func main() {
fmt.Println(getA(), getB())
}

func getA() (a int) {
a += 1
defer func() {
a += 1
}()
return a
}

func getB() int {
a := 0
a += 1
defer func() {
a += 1
}()
return a
}

结果输出什么?
AnroZ
306 天前
理解的问题吧,
和 C++的 RAII 类似,defer 是遵循执行顺序的,也当然支持条件语句,
所以只有逻辑执行到了才会触发。
golang 的这个特性我觉得挺好的,包括并发的时候 happens-before ,逻辑可见即所得
zhujinliang
306 天前
实际使用中 defer 在 return 之后的情况很多

比如
f, err := os.Open("foo.txt")
if err != nil {
return err
}
defer f.Close()

正因为 defer 这个特性,如果打开失败了,也就不用关闭了
kneo
306 天前
虽然我知道这个系列质量不高,但还是忍不住吐槽:这也叫陷阱吗……
yplam
305 天前
发一个

```

func checkVal() (b bool) {
defer func() {
println("b", b)
}()
b = true
return false
}

```
zhwguest
305 天前
我最初犯的错误是在代码块(花括号)中使用 defer 了,后来才发现这货只针对函数调用,草率了....
Carlgao
305 天前
@yplam 严格来说这个是闭包的问题,不是 defer 的问题
ted0220
305 天前
对于新手来说最大的陷阱就是,defer 语句中的变量,在 defer 声明时就决定了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1010378

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX