• go 语言之defer


    defer

    对于go语言里面的defer关键字来说,是表示延迟调用,通常用于关闭一些资源,比如打开的文件资源,socket连接,同时也配合recover函数来处理panic的异常。
    1、单个defer例子:

    func test1(){
    	fmt.Println("start")
    	defer fmt.Println("defer")
    	fmt.Println("end")
    }
    
    func main() {
    	test1()
    }
    

    上述输出结果是:

    start
    end
    defer
    

    2、多个defer例子

    func test1(){
    	fmt.Println("start")
    	defer fmt.Println("defer1")
    	defer fmt.Println("defer2")
    	fmt.Println("end")
    }
    
    func main() {
    	test1()
    }
    

    输出结果

    start
    end
    defer2
    defer1
    

    说明:对于多个defer来说,执行的顺序与定义的顺序是相反的。
    比如:对于上述的代码,在执行到第一个defer的时候,go编译器会把当前的derfer放到一个栈里面,然后执行下一行代码,发现下一行代码也是defer,那么也会放到同一个栈(因为属于同一个函数作用域),当函数执行完成以后,准备返回时,发现还有defer语句没有执行,那么就会从栈里面把defer语句拿出来执行。由于栈是先进后出,也就说明了defer是先定义后执行了。

    3、defer执行的时机在说明
    一般来说,对于函数没有返回值的情况下,defer并不影响最终的结果,当函数有返回值时,来看看下面的一个例子:

    func test2() int{
    	x := 1
    	defer func ()  {
    		x++
    	}()
    
    	return x
    }
    
    func main() {
    	fmt.Println(test2())
    }
    

    执行结果:

    1
    

    可以发现,函数最终返回的结果是1,而不是2.
    说明:
    go语言当中 return并不是原子性的,对于 return x来说,首先执行的是对x赋值,然后在执行return。二defer关键字的执行时机就是在x赋值之后,return之前。
    那么为什么最终返回的是1而不是2呢?
    个人理解如下:
    由于函数的返回值是没有命名的返回值类型,所以当执行到return x以后,保存的是x这个变量的副本,但是由于x是值类型,所以这个副本里面存储的是真真实实的int类型,也就是1,所以后续在defer里面对x++,改变的是x的值,对于return后面的副本来说是不会修改的。其实这有点类似函数的形参与实参的区别。

    那么再来看一个下面的例子:

    func test2() []int{
    	x := []int{1,2,3}
    	defer func ()  {
    		x[0] = 10
    	}()
    
    	return x
    }
    
    func main() {
    	fmt.Println(test2())
    }
    

    返回结果:

    [10 2 3]
    

    其实这就跟上述说的一致,return x语句的x保存的是一个副本,但是由于x是一个引用类型,所以在defer里面进行对x修改以后,最终的x值也就发生了变化。

    在来看一个命名返回值参数类型的函数

    func test3() (x int){
    	defer func ()  {
    		x = 20
    	}()
    
    	x = 10
    	return
    }
    
    func main() {
    	fmt.Println(test3())
    }
    

    函数返回值:

    20
    

    为什么是20呢?
    这是因为这是一个命名返回值的函数,在go语言当中,命名返回值当中的x就已经是一个实实在在的变量了,所以当在函数当中进行修改的时候,最终都是修改的这个x值。
    同理,看一下下面这个函数的返回值是什么:

    func test3() (x int){
    	defer func ()  {
    		x = 20
    	}()
    
    	x = 10
    	return 5
    }
    
    func main() {
    	fmt.Println(test3())
    }
    

    这里依然返回20,因为命名返回值来说,返回的就是x的值。跟5就没什么关系了。

    记录学习和生活的酸甜苦辣.....哈哈哈
  • 相关阅读:
    Day2----Python常用模块
    Day1--Python基础知识
    AES加密
    MOS管基本MOS管基本认识(快速入门)认识(快速入门)
    printf定义宏方便调试
    ESP8266上电透传与手动透传AT指令设置笔记
    三态门与高阻态
    步进电机原理
    关于stm32 MCU申请动态内存malloc的认识
    高低位数据分离的两种方法
  • 原文地址:https://www.cnblogs.com/yjt1993/p/14613599.html
Copyright © 2020-2023  润新知