0基础小白的Golang学习之路--05--函数(下),init函数、闭包、defer关键字

目录

init函数

闭包

问题1:为什么用闭包?

问题2:闭包为什么能保存之前的结果?

问题3:什么时候用闭包?

defer关键字

defer的作用

例子

defer应用场景

字符串函数


本次记录主要是对init函数进行了解,感受它的运行顺序,深入的思考闭包到底是什么,虽然再Python中也有接触闭包,但是Go中的闭包到底怎么做的?我们该怎么用?用在什么地方?最后是学习一下defer关键字。

init函数

        init函数,其实在很多语言中都有类似的函数,比如Python中类内的init函数,或者我们项目中自己设置的init初始化函数。在Go语言中init函数是系统设定好的函数,执行顺序不需要我们自己去定义。

(1)init函数:初始化函数,可以用来进行一些初始化的操作每一个源文件都可以包含一个init函数,该函数会在main函数执行前,被Go运行框架调用

(2)全局变量定义,init函数,main函数的执行流程?

(3)多个源文件都有init函数的时候,如何执行?

由上图我们可以看到,我们在导其他包时,先会对其他包进行初始化,然后再对本文件的函数进行初始化。其次,需要注意的一点是,其他文件的变量定义需要大写,并且不能放到init函数内部,有的时候编译出现变量未使用,也不一定是没有使用变量,有可能是在该变量的生命周期内没有使用到,也就是变量的作用域需要做一下改变 。

闭包

        闭包是一个函数与其引用的外部变量组合的包装体。当一个函数内部定义了一个匿名函数,并且该匿名函数引用了外部的变量,那么就形成了闭包。闭包包含了这个匿名函数以及与之相关的外部变量的引用。

package main
import "fmt"
//闭包:返回的匿名函数+匿名函数以外的变量
func calSum() func(num int)int{
    var sum int = 0//变量,他相对于内部的匿名函数就是全局变量
    return func(num int)int{//匿名函数
        sum+=num
        return sum
    }
}
func main(){
    f := calSum()
    fmt.Println(f(1))//0+1
    fmt.Println(f(2))//1+2
    fmt.Println(f(3))//3+3
}

这样,我们就知道了闭包的使用方法,即:闭包 = 匿名函数 + 匿名函数以外的变量。那么问题就来了,我们为什么要用闭包,闭包为什么能保存前一次的执行结果,我们什么时候用闭包呢?

问题1:为什么用闭包?

闭包可以帮助我们不使用全局变量或者类似递归这种方法就获取到之前的函数运行结果,以实现类似累加等功能

问题2:闭包为什么能保存之前的结果?

闭包中捕获的外部变量是实际存储在堆上的变量,而不是栈上的副本。这意味着每当闭包中的函数被调用时,它将引用并访问相同的外部变量。因此,闭包可以在多次调用之间保持对同一份外部变量的引用。

具体而言,当闭包函数生成时,它会捕获外部变量的引用,并将其保存在闭包的内部,称之为闭包的环境或闭包的状态。每次调用闭包函数时,它都可以访问和修改这些保存在闭包环境中的变量,以及在前一次调用中保存的结果。

问题3:什么时候用闭包?

特性使得闭包可以实现类似于迭代器、记忆化、状态保持等功能,而无需使用全局变量或静态变量。闭包能够在每次调用时,记住外部环境的状态,并根据前一次的结果进行计算或处理。

思考:那么为什么要用闭包不用全局变量呢?需要前面的数据我直接就定义全局变量不更简单更直接么?

因为全局变量太死板、固定并且不安全,反观闭包来看,闭包因为它的密封性更安全,也更灵活,不像全局变量那样能被本文件中的其他部分访问到,比如闭包中的sum,只有在这个函数内才能访问到,不会在本文件的其他函数中访问到,这就是闭包相比于全局变量更优势的地方!

defer关键字

defer的作用

创建资源,能够在函数执行完毕后及时的释放资源,有点类似C++中的RAII机制,只不过是延迟释放掉而已

例子

案例1

案例2

defer应用场景

比如你想关闭某个使用的资源,在使用的时候直接随手defer,因为defer有延迟执行机制(函数执行完毕再执行defer压入栈的语句)所以你用完随手写了关闭,比较省心,省事

==================================分割线==================================

字符串函数

        这里其实就是对字符串处理的一个特殊方式,然后特殊记录一下,就是for-range和切片的处理方式,值得一提得是,可以对汉字进行处理输出。

package main
import "fmt"
func main(){
    str := "你好,三冬拾柒"
    //方法一:用for-range语句实现字符串单个输出
    for _,val := range str{
        fmt.Printf("%c",val)
    }
    fmt.Println()
    //方法二:切片输出
    r := []rune(str)
    for i:=0;i<len(r);i++{
        fmt.Printf("idnex:%d   val:%c\n",i,r[i])
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值