文章目录
defer的使用场景
- 释放资源(连接数据库之后defer等)
- 记录日志
- 加锁解锁
defer的三大特性
defer函数的传入参数在定义时就已经明确
func main() {
i := 1
defer fmt.Println(i)
i++
return
}
上面代码输出1,而不是2
defer函数是按照后进先出的顺序执行
func main() {
for i := 1; i <= 5; i++ {
defer fmt.Print(i)
}
}
上面代码输出54321,而不是12345
defer函数可以读取和修改函数的命名返回值
func main() {
fmt.Println(test())
}
func test() (i int) {
defer func() {
i++
}()
return 100
}
上面代码输出输出101,而不是100或者1
defer对有名返回值和无名返回值的影响
有名返回值即已经定义了函数的返回对象,无名返回值即只定义了函数的返回类型,没有定义返回对象
func f1() res int {
// 有名返回值,返回值为res
}
func f2() int {
// 无名返回值
}
package main
import "fmt"
func main() {
fmt.Println("f1 result: ", f1())
fmt.Println("f2 result: ", f2())
}
func f1() int {
var i int
defer func() {
i++
fmt.Println("f11: ", i)
}()
defer func() {
i++
fmt.Println("f12: ", i)
}()
i = 1000
return i
}
func f2() (i int) {
defer func() {
i++
fmt.Println("f21: ", i)
}()
defer func() {
i++
fmt.Println("f22: ", i)
}()
i = 1000
return i
}
返回结果为:
f12: 1001
f11: 1002
f1 result: 1000
f22: 1001
f21: 1002
f2 result: 1002
原理:
return会将返回值先保存起来。
对于无名返回值来说:返回值保存在临时对象中,defer无法处理这个临时对象
对于有名返回值来说:就保存在已命名的变量中,defer可以处理这个临时对象
defer匿名函数的各种情况
以下对defer的不同情况做讨论:
package main
import "fmt"
func main() {
fmt.Println(f1())
fmt.Println(f2())
fmt.Println(f3_1())
fmt.Println(f3_2())
fmt.Println(f4())
fmt.Println(f5())
}
func f1() int {
x :=5
defer func() {
x++
}()
return x
}
假设无名返回变量为return_value
return x之后,return_value
被赋予了x的值(5)
defer对x的改变不影响return_value
f1的返回结果为5
func f2() (x int) {
defer func() {
x++
}()
return 5
}
f2定义了返回的对象为x
return 5之后,x的值变为5
defer可以波及f2的返回值,故defer里面的x++就是返回值的自增
f2结果为6
func f3_1() (y int) {
x :=5
defer func() {
x++
}()
return x
}
此处f3_1是有名返回值,返回参数的名字是y
return x之后将x的值(5)赋予给y,之后defer将f3_1内部的参数x做自增处理,x的值为6,但是y的值不变,是5
f3_1结果是5
func f3_2() (y int) {
x :=5
defer func() {
y++
}()
return x
}
函数f3_2是有名返回值,返回参数的名字是y
return x的时候将f3_2函数内部定义变量x的值(5)赋予给了y,此时y的值是5
defer对y做自增操作,此时y的值变为6
f3_2返回结果是6
func f4() (x int) { // 第一行: f4的有名返回参数x
defer func(x int) { // 第二行: defer的输入形参x
x++ // 第三行: defer的输入形参x
}(x) // 第四行: 将f4的有名返回参数的值赋给defer匿名函数
return 5
}
f4函数返回有名返回值x
return 5之后,赋予了f4函数的返回参数x,给了5这个值
然后defer函数体后面接了(x),表示将f4返回参数x的值下发给了defer匿名函数
defer的匿名函数有自己的形参x(第二行的那个x),f4将自己返回参数的值给了defer的形参x
defer对自己的形参做自增操作并不会影响f4的返回参数。所以最终的返回结果还是5
f4结果为5
func f5() (x int) {
x = 5
defer func(x int) {
x++
}(x)
return x
}
f5返回结果为5