大家一起学Golang——函数、闭包、defer、recover

大家一起学Golang——函数、闭包、defer、recover

函数执行流程

go代码编译完后,函数会以计算机指令的方式存放在代码区,函数定义的形参局部变量没有调用的时候 是不占用内存,只有调用时会加载到内存中。

在介绍计算机指令形式的代码在内存运行的状况前,先要说下栈(stack),几乎每个程序都使用栈,这个栈满足先进后出的顺序,保存函数调用所需要的信息,被称为堆栈帧(stack frame)
一个函数调用所需要的信息:

  1. 函数返回的地址
  2. 函数的参数
  3. 保存的上下文

下例子来分析函数在栈中情况:

func demoAppend(slice []int){
	slice = append(slice, 4,5,6)
}
func main(){
	slice := [] int{1,2,3}
	demoAppend(slice)
	fmt.Println(slice)
}

在这里插入图片描述

闭包

函数分为:具名函数和匿名函数
具名函数对应于包级的函数,是匿名函数的一种特例。
当匿名函数引用外部作用域的变量就变成闭包函数,闭包函数是函数式编程语言的核心。
闭包是将函数内部和函数外部连接起来的桥梁
作用:

  • 可以读取函数的内部变量
  • 变量始终保存在内存当中(与全局变量作用相当)
//闭包函数的一个例子,defer 执行了匿名函数,捕获外部变量v 以引用的方式,这个匿名函数就是闭包
func Demo() (v int){
	defer func(){
		v++
	}()
	return 1
}

使用闭包也要注意,调用的局部变量会保存在内存中,会导致内存滥用,使性能降低,要在退出函数前,删除掉不适用的局部变量。

defer

⼀个函数中有多个defer语句,它们会以LIFO(后进先出)的顺序执行。
作用:

  1. 释放占用的资源,如关闭文件,关闭数据库连接,网络连接
  2. 捕捉处理异常
  3. 输出日志

下面是个有趣的例子,需要借助对内存栈中的理解,分析defer的调用

func main(){
    for i:=0;i<3;i++ {
        i:=i   //每次循环产生申请一个i变量空间
        defer func(){
            fmt.Println(i)
        }()
    }
}
//输出:2 1 0 

func main(){
    for i:=0;i<3;i++ {
        defer func(){
            fmt.Println(i)
        }()
    }
}
//输出:3 3 3

之前,讨论函数 内存栈中的存储逻辑,分析defer 调用 i局部变量的情况。
可见go语言中,分析内存 对理解代码非常帮助。

recover错误拦截

专用于拦截运行时panic的内建函数,常见和defer写在一起来捕获异常。

func Demo(i int) {
	var arr [10]int
	//设置错误拦截 defer + 匿名函数 +recover
	defer func() {
		err := recover()
		//没有异常不会打印错误
		if err != nil {  
			fmt.Println(err)
		}
	}()
	//数组下标越界
	arr[i] = 119

}
func main() {
	Demo(10)
}

捕捉错误:runtime error: index out of range [10] with length 10

发布了31 篇原创文章 · 获赞 5 · 访问量 7701

猜你喜欢

转载自blog.csdn.net/c0586/article/details/104211174