go的defer和闭包示例说明(非内部实现)
作者:牙小木木
这篇文章主要为大家介绍了go的defer和闭包示例说明(非内部实现),有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
golang的闭包函数
用几个例子说明golang的闭包函数,结合defer使用,配合对应代码及文末总结。
函数 | 说明 | 输出 |
---|---|---|
e1 | defer调用,相当于是拿到了当前err变量的快照,即注册defer函数的时候,将当下err的值塞入到defer中 | start err1 |
e2 | defer 调用,但是一个闭包函数,且闭包函数有传参,闭包捕获当前err的值仍然是 start err2(闭包捕获的是变量值的拷贝),且闭包内的值变量改变不会影响外部err的值(详见见e5) | start err2 |
e3 | defer 调用,闭包内的变量和匿名函数外的变量是公用的,没有传递形参,没有传递形参,与上下文共享 | defer3 error |
e4 | defer 调用,在函数 e4 中,当你将 err 作为参数传递给闭包函数时,实际上是创建了一个闭包函数的副本,这个副本在闭包内部独立于外部作用域。这种行为是因为闭包在捕获外部变量时,会将外部变量的当前值复制到闭包内部,形成一个闭包环境,现在理解了闭包的概念了吧。具体来说,在 defer 语句执行的时候,闭包函数会将 err 的当前值(即 "start err4")复制到闭包内部的参数中。之后,无论外部作用域的 err 是否发生改变,闭包内部的参数值都会保持不变,因为闭包已经捕获了一个快照 | start err4 |
e5 | 传值的情况下,闭包内的值变量改变不会影响外部err的值,(互相独立) | now err is start err5 start err5CHANGE ME |
e6 | 闭包没有传值,拿到的err是最后赋值的, | now err is start err6 defer6 error CHANGE ME |
package main import ( "errors" "fmt" ) func e1(){ err := errors.New("start err1") defer fmt.Println(err) err = errors.New("defer1 error") return } func e2(){ err := errors.New("start err2") defer func(e error) { fmt.Println(e) }(err) err = errors.New("defer2 error") return } func e3(){ err := errors.New("start err3") //闭包内的变量和匿名函数外的变量是公用的,没有传递形参,没有传递形参,与上下文共享 defer func() { fmt.Println(err) }() err = errors.New("defer3 error") return } func e4(){ var err error err = errors.New("start err4") //闭包内的变量和匿名函数外的变量是公用的,但是如果传了形参,那就和上文的共用了 //在函数 e4 中,当你将 err 作为参数传递给闭包函数时,实际上是创建了一个闭包函数的副本,这个副本在闭包内部独立于外部作用域。这种行为是因为闭包在捕获外部变量时,会将外部变量的当前值复制到闭包内部,形成一个闭包环境 //具体来说,在 defer 语句执行的时候,闭包函数会将 err 的当前值(即 "start err4")复制到闭包内部的参数中。之后,无论外部作用域的 err 是否发生改变,闭包内部的参数值都会保持不变,因为闭包已经捕获了一个快照。 defer func(err error) { fmt.Println(err) }(err) err = errors.New("defer4 error") return } func e5(){ err := errors.New("start err4") defer func(err error ) { err=errors.New(err.Error()+"CHANGE ME") fmt.Println(err) }(err) fmt.Println("now err is ",err) err = errors.New("defer5 error") return } func e6() { err := errors.New("start err6") defer func() { err = errors.New(err.Error() + " CHANGE ME") fmt.Println(err) }() fmt.Println("now err is ", err) err = errors.New("defer6 error") return } func main(){ e1() e2() e3() e4() e5() e6() }
变量作用域和闭包
Go 语言中的变量作用域由代码块决定。变量在其定义的代码块内可见。
闭包是一个函数值,它可以捕获其定义时周围的作用域内的变量。
闭包可以在定义之外被调用,仍然访问并修改捕获的变量。
闭包和变量捕获
闭包函数可以捕获外部作用域的变量。在闭包内部,它们可以访问外部变量的值。
闭包捕获的变量是其副本,即闭包内部使用的是变量值的拷贝。
修改闭包内部捕获的变量不会影响外部作用域中的变量,除非你在闭包内直接修改外部作用域的变量。
闭包参数传递
在闭包内部接收外部作用域的变量作为参数,可以使闭包操作外部作用域的变量。
使用闭包参数传递可以有效隔离闭包内外的变量,从而保持可预测性。
在 defer 中的闭包
当在 defer 语句中使用闭包时,闭包内部的变量会被“捕获”并在 defer 执行时使用。
在闭包内部修改闭包捕获的变量不会影响外部作用域中的变量,除非你直接修改外部作用域的变量。
总结
闭包是一种强大的概念,可以使函数拥有状态并延迟执行。
了解闭包如何操作变量作用域,以及它们如何捕获和修改变量,是编写高效、清晰的 Go 代码的关键。
当在闭包中操作变量时,要注意变量作用域、捕获的变量副本和对外部作用域的影响。
以上就是go的defer和闭包示例说明(非内部实现)的详细内容,更多关于go defer闭包的资料请关注脚本之家其它相关文章!