zoukankan      html  css  js  c++  java
  • golang 详解defer

    什么是defer

    defer用来声明一个延迟函数,把这个函数放入到一个栈上, 当外部的包含方法return之前,返回参数到调用方法之前调用,也可以说是运行到最外层方法体的"}"时调用。我们经常用他来做一些资源的释放,比如关闭io操作
     
    func doSomething(fileName string) {
        file,err := os.Open(fileName)
        if err != nil {
        panic(err)
        }
        defer file.Close()
    }
    defer 可以保证方法可以在外围函数返回之前调用。有点像其他言的 try finally
    try{
    }finally{
    }
     

    defer 读写外部变量

      defer声明的函数读写外部变量,和闭包差不多。比如下面的代码

    func doSomething() {
        v := 10
        defer func() {
            fmt.Println(v)
            v++
            fmt.Println(v)
        }()
        v += 5
    }

    输出为

    15
    16

      就像闭包一样,如果不是defer函数方法内的变量会向上一层函数访问变量,重新做计算。

    defer 读写命名的返回值

        这个例子中,defer声明的方法,给命名的返回值自增1
     
    1 func doSomething() (rev int) {
    2     defer func() {
    3         rev++
    4     }()
    5 
    6     return 5
    7 }

      第6行的return 相当于

    return rev = 5

      defer 声明的匿名函数会在return 之前执行,相当于

    rev = 5
    // 执行defer方法
    rev++
    //然后return
    return

      所以结果是6

      我把代码做一点点修改

    1 func doSomething() (rev int) {
    2     v := 10
    3     defer func() {
    4         v++
    5     }()
    6 
    7     return v
    8 }

      第7行返回的是局部变量v.   

    return v 相当于 return rev = v

      defer 函数里是对局部变量v的操作,所以与返回的rev没有关系。所有执行的结果是:10

    defer 执行顺序

    当有多个defer时执行顺序逆向的,后进先出:
    func doSomething() {
        defer fmt.Println(1)
        defer fmt.Println(2)
    }
    会先输出2,再输出1
     

     defer 处理异常

      panic抛出异常后,如果不处理应用程序会崩溃。为了防止程序崩溃,我们可以在defer的函数里使用recover来捕获中异常:
    func doSomething() {
        defer func() {
            if err := recover(); err != nil {
                fmt.Print(err)
            }
            
        }()
    
        fmt.Println("Running...")
        panic("run error")
    }

    输出:

    Running...
    run error

    recover 会捕获panic的异常。我再把代码做一点点修改:

    func doSomething() {
        defer func() {
            if err := recover(); err != nil {
                fmt.Print(err)
            }
            
        }()
    
        defer func() {
            panic("defer error")
        }()
    
        fmt.Println("Running...")
        panic("run error")
    }

    输出结果

    Running...
    defer error

    因为 recover()只捕获最后一次panic

     
  • 相关阅读:
    Keepass无法导入密钥文件
    数据库交互方式之一
    Grey encoder and decoder
    SystemVerilog 序列运算符与属性运算符
    避免int 与 pointer的隐式类型转换
    xxx.lib(xxx.obj)fatal error LNK1103: debugging information corrupt; recompile module 的解决方案
    c++ static 关键字用法
    影响中国软件开发的人(摘录)
    链接
    有助于事业发展和幸福感提升的四个约定
  • 原文地址:https://www.cnblogs.com/li-peng/p/8552089.html
Copyright © 2011-2022 走看看