乐趣区

关于golang:Go常见坑Go语言里被defer的函数一定会执行么

前言

大家都晓得 Go 编程中,假如在函数 F 里,执行了 defer A(),那在函数 F 失常 return 之前或者因为 panic 要完结运行之前,被 defer 关键字润饰的函数调用 A()都会被执行到。

比方上面的 2 个例子:

test1()会在 main 完结之前执行

// defer1.go
package main

import ("fmt")

func test1() {fmt.Println("test")
}

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

这个例子输入的后果是:

main start
main end
test

test1()会在 panic 之前执行

// defer2.go
package main

import ("fmt")

func test1() {fmt.Println("test")
}

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

这个例子输入的后果是:

main start
test
panic: 1

goroutine 1 [running]:
main.test2(...)
        /path/to/defer2.go:13
main.main()
        /path/to/defer2.go:18 +0xb8
exit status 2

问题

如果在函数 F 里,defer A()这个语句执行了,是否意味着 A()这个函数调用肯定会执行?

这里大家能够先脑补一会。

请看上面的例子:

// defer3.go
package main

import (
    "fmt"
    "os"
)

func test1() {fmt.Println("test")
}

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

下面的代码运行后果会是怎么样?

论断

下面 defer3.go 执行的后果是:

main start
main end

被 defer 的 test1()并没有在 main 完结之前执行。这是为什么呢?

查看 os.Exit 的阐明如下:

Exit causes the current program to exit with the given status code. Conventionally, code zero indicates success, non-zero an error. The program terminates immediately; deferred functions are not run.

For portability, the status code should be in the range [0, 125].

如果在函数里是因为执行了 os.Exit 而退出,而不是失常 return 退出或者 panic 退出,那程序会立刻进行,被 defer 的函数调用不会执行。

defer 4 准则回顾

  1. defer 前面跟的必须是函数或者办法调用,defer 前面的表达式不能加括号。

    defer (fmt.Println(1)) // 编译报错,因为 defer 前面跟的表达式不能加括号
  2. 被 defer 的函数的参数在执行到 defer 语句的时候就被确定下来了。

    func a() {
        i := 0
        defer fmt.Println(i) // 最终打印 0
        i++
        return
    }

    上例中,被 defer 的函数 fmt.Println 的参数 i 在执行到 defer 这一行的时候,i的值是 0,fmt.Println 的参数就被确定下来是 0 了,因而最终打印的后果是 0,而不是 1。

  3. 被 defer 的函数执行程序满足 LIFO 准则,后 defer 的先执行。

    func b() {
        for i := 0; i < 4; i++ {defer fmt.Print(i)
        }
    }

    上例中,输入的后果是 3210,后 defer 的先执行。

  4. 被 defer 的函数能够对 defer 语句所在的函数的命名返回值做读取和批改操作。

    // f returns 42
    func f() (result int) {defer func() {
            // result is accessed after it was set to 6 by the return statement
            result *= 7
        }()
        return 6
    }

    上例中,被 defer 的函数 func 对 defer 语句所在的函数 f 的命名返回值 result 做了批改操作。

    调用函数f,返回的后果是 42。

    执行程序是函数 f 先把要返回的值 6 赋值给 result,而后执行被 defer 的函数 func,result 被批改为 42,而后函数 f 返回 result,也就是返回了 42。

    官网阐明如下:

    Each time a "defer" statement executes, the function value and parameters to
    the call are evaluated as usual and saved anew but the actual function is not 
    invoked. Instead, deferred functions are invoked immediately before the 
    surrounding function returns, in the reverse order they were deferred. That
    is, if the surrounding function returns through an explicit return statement, 
    deferred functions are executed after any result parameters are set by that 
    return statement but before the function returns to its caller. If a deferred
    function value evaluates to nil, execution panics when the function is 
    invoked, not when the "defer" statement is executed.

代码

相干代码和阐明开源在 GitHub:https://github.com/jincheng9/…

也能够搜寻公众号:coding 进阶,查看更多 Go 常识。

一起提高!

退出移动版