go的defer和闭包示例说明(非内部实现)

 更新时间:2023年08月20日 10:03:50   作者:牙小木木  
这篇文章主要为大家介绍了go的defer和闭包示例说明(非内部实现),有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

golang的闭包函数

用几个例子说明golang的闭包函数,结合defer使用,配合对应代码及文末总结。

函数说明输出
e1defer调用,相当于是拿到了当前err变量的快照,即注册defer函数的时候,将当下err的值塞入到defer中start err1
e2defer 调用,但是一个闭包函数,且闭包函数有传参,闭包捕获当前err的值仍然是 start err2(闭包捕获的是变量值的拷贝),且闭包内的值变量改变不会影响外部err的值(详见见e5)start err2
e3defer 调用,闭包内的变量和匿名函数外的变量是公用的,没有传递形参,没有传递形参,与上下文共享defer3 error
e4defer 调用,在函数 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闭包的资料请关注脚本之家其它相关文章!

相关文章

  • golang踩坑实战之channel的正确使用方式

    golang踩坑实战之channel的正确使用方式

    Golang channel是Go语言中一个非常重要的特性,除了用来处理并发编程的任务中,它还可以用来进行消息传递和事件通知,这篇文章主要给大家介绍了关于golang踩坑实战之channel的正确使用方式,需要的朋友可以参考下
    2023-06-06
  • Go实现比较时间大小

    Go实现比较时间大小

    这篇文章主要介绍了Go实现比较时间大小的方法和示例,非常的简单实用,有需要的小伙伴可以参考下。
    2015-04-04
  • golang的时区和神奇的time.Parse的使用方法

    golang的时区和神奇的time.Parse的使用方法

    这篇文章主要介绍了golang的时区和神奇的time.Parse的使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • Go并发的方法之goroutine模型与调度策略

    Go并发的方法之goroutine模型与调度策略

    在go中,协程co-routine被改为goroutine,一个goroutine只占几kb,因此可以有大量的goroutine存在,另一方面goroutine 的调度器非常灵活,本文给大家介绍下Go并发的方法之goroutine模型与调度策略,感兴趣的朋友一起看看吧
    2021-11-11
  • 详解Golang如何在编译时注入版本信息

    详解Golang如何在编译时注入版本信息

    这篇文章主要为大家详细介绍了Golang如何在编译时实现注入版本信息,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的可以了解一下
    2023-06-06
  • 获取Golang环境变量的三种方式小结

    获取Golang环境变量的三种方式小结

    本文介绍了Golang中获取环境变量的三种方式,包含使用Viper包、GoDotEnv包和os包,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-11-11
  • Golang unsafe.Sizeof函数代码示例使用解析

    Golang unsafe.Sizeof函数代码示例使用解析

    这篇文章主要为大家介绍了Golang unsafe.Sizeof函数代码示例使用解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • Go 为什么不支持可重入锁原理解析

    Go 为什么不支持可重入锁原理解析

    这篇文章主要为大家介绍了Go 为什么不支持可重入锁原理解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08
  • golang包循环引用的几种解决方案总结

    golang包循环引用的几种解决方案总结

    golang有包循环引用问题,用过的应该都知道,下面这篇文章主要给大家介绍了关于golang包循环引用的几种解决方案,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • golang 接口嵌套实现复用的操作

    golang 接口嵌套实现复用的操作

    这篇文章主要介绍了golang 接口嵌套实现复用的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04

最新评论