Golang Go语言中延迟调用的问题
Golang Go语言中延迟调用的问题
package main
import “fmt”
func main() {
for i := 0; i < 3; i++ {
defer func() {
fmt.Println(“a:”, i)
}()
}
}
输出是:
a:3
a:3
a:3
package main
import “fmt”
func main() {
for i := 0; i < 3; i++ {
i := i
defer func() {
fmt.Println(“a:”, i)
}()
}
}
输出是:
a:2
a:1
a:0
为什么两个的运行结果会不一样呢?
更多关于Golang Go语言中延迟调用的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在循环结束时 defer 才会执行,
第一个输出的是 for 语句的 i 的值,这时候 i 已经是 3 了( (3<3)!=true,循环结束 )。
第二个输出的是局部变量 i,当然是 2、1、0.
不过我有个疑问,如何理解第二个回答中的例子
两个关键点:
1. 所有循环步共享同一个循环变量 i
2. 延迟调用在循环之后(程序退出之前)执行
第二个例子中的左 i 和右 i (循环变量)不同,每个循环步有自己独立的左 i
第一个只有一个变量;第二个有四个变量
闭包是引用传值
第二个循环中每次都会定义 i,闭包中引用的是每次新定义的 i 的值,依次是 0 1 2,defer 先入后出打印出来就是 2 1 0
闭包传值问题。go 是按值传递,参见 https://github.com/golang/go/wiki/CommonMistakes
go 只有按值传递,没有引用传值,有值类型和引用类型,楼主的问题是 loop goroutime 的执行问题
在Golang(Go语言)中,延迟调用通常通过内置的 defer
关键字来实现。defer
语句会将一个函数调用延迟到包含它的函数即将返回时执行,这常用于资源清理、解锁互斥锁、关闭文件或网络连接等操作。
使用场景
- 资源释放:在文件操作或数据库连接中,使用
defer
确保资源在函数退出时被正确释放。 - 互斥锁解锁:在多线程编程中,通过
defer
确保互斥锁在函数结束时被解锁,避免死锁。 - 日志记录:在函数入口和出口处记录日志,通过
defer
实现函数结束时自动记录退出日志。
注意事项
- 执行顺序:
defer
语句按照后进先出的顺序执行,即最后defer
的函数最先执行。 - 参数求值:
defer
语句中的函数参数在defer
时立即求值,而不是在函数实际执行时求值。 - 异常处理:即使在发生panic时,
defer
语句也会被执行,这对于恢复程序的正常运行或记录错误信息非常有用。
示例
func readFile(filename string) {
file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
}
defer file.Close() // 确保文件在函数结束时被关闭
// 处理文件内容
}
总之,defer
是Go语言中一个非常有用的特性,它简化了资源管理,并提高了代码的健壮性和可读性。