• 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

     
  • 相关阅读:
    linux内存查看方法
    setInterval/setTimeout传参方法
    MBT简述:基于模型的测试
    mac如何挂载移动硬盘、存储设备、U盘
    Jquery获取元素方法
    jquery如何判断元素是否被点击、属性操作、class操作
    SQL Server数据库中还原孤立用户的方法集合
    密码有效性验证失败。该密码不够复杂,不符合 Windows 策略要求
    还原SQLServer2008数据库报用户无法登录 .
    disable jboss JMXInvokerServlet .
  • 原文地址:https://www.cnblogs.com/li-peng/p/8552089.html
Copyright © 2020-2023  润新知