zoukankan      html  css  js  c++  java
  • 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就没什么关系了。

    记录学习和生活的酸甜苦辣.....哈哈哈
  • 相关阅读:
    MFC tab页面中获到其它页面的数据
    sqlite数据库中"Select * From XXX能查到数据,但是Select DISTINCT group From xxx Order By group却查不出来
    关闭程序出现崩溃(exe 已触发了一个断点及未加载ucrtbased.pdb)
    springboot 通用Mapper使用
    springBoot 发布war包
    springCloud Zuul网关
    springboot hystrix turbine 聚合监控
    springBoot Feign Hystrix Dashboard
    springBoot Ribbon Hystrix Dashboard
    springBoot Feign Hystrix
  • 原文地址:https://www.cnblogs.com/yjt1993/p/14613599.html
Copyright © 2011-2022 走看看