关于golang:golang-defer详细讲解

Golang开发文档 https://www.topgoer.com/%E5%8…

defer个性:

  1. 关键字 defer 用于注册提早调用。
  2. 这些调用直到 return 前才被执。因而,能够用来做资源清理。
  3. 多个defer语句,按先进后出的形式执行。
  4. defer语句中的变量,在defer申明时就决定了。

defer用处:

  1. 敞开文件句柄
  2. 锁资源开释
  3. 数据库连贯开释

依据开发文档形容,上面来做一一验证。

1.defer用于注册提早调用。

package main

import "fmt"

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

执行后果为:

证实defer函数用来提早调用,在函数完结的时候被调用。函数完结包含:被调用办法失常return,或者达到办法体结尾,也或者蕴含defer函数的办法在执行panic的时候都会执行defer函数。

值得注意是,当蕴含defer函数的办法在执行panic操作的时候,会先执行defer函数,再执行panic办法,panic之后的语句是不可达的。上面我用实例来再次证实一下。

package main

import "fmt"

func main()  {
    fmt.Println("测试defer start")
    defer func() {
        fmt.Println("defer func")
    }()
    fmt.Println("测试defer end")
    panic("panic 异样")
}

执行后果为:

由此看出,defer产生在panic执行之前,因而,能够在defer办法外面做资源清理,开释操作。

2.多个defer语句,按先进后出的形式执行。

package main

import "fmt"

func main()  {
    deferFunc1()
}

func deferFunc1()  {

    val := "1111"
    defer fmt.Println("val1",val)
    defer func() {
        fmt.Println("val2",val)
    }()
    defer fmt.Println("val3",val)

    defer func(val string) {
        fmt.Println("val4",val)
    }(val)
    defer fmt.Println("val5",val)

    fmt.Println("val",val)
}

执行后果为:

简略了解就是:定义defer相似于入栈操作,执行defer相似于出栈操作,先进后出。

3.defer语句中的变量,在defer申明时就决定了。

package main

import "fmt"

func main()  {
    deferFunc1()
}

func deferFunc1()  {

    val := "1111"
    defer fmt.Println("val1",val)
    defer func() {
        fmt.Println("val2",val)
    }()
    defer fmt.Println("val3",val)

    val = "2222"
    defer func(val string) {
        fmt.Println("val4",val)
    }(val)
    defer fmt.Println("val5",val)

    val = "3333"
    defer func() {
        fmt.Println("val6",val)
    }()
    fmt.Println("val",val)
}

此时,能够考虑一下下面程序输入后果是啥?为什么?针对下面程序有几个易错点,常常被作为面试的口试题来考查求职者对defer的了解。

上面看一张很经典的图片,golang程序调用程序图。

var 这些变量是依照由上到下赋值的,联合下面程序来说,val变量最初被赋值为”3333″,而defer又是推延函数,按理说所有defer蕴含的提早函数的val都是”3333″才对,然而执行后果出乎咱们的预料。

由下面后果能够看出:
defer间接执行fmt.Println函数,val变量的值对应的由上到下最近赋值变量的值。
defer执行func(){}()时,val变量的值对应最初赋值的值。这里还有一种非凡状况,defer func(val string) {}(val) 将变量传递到defer函数外面,此时func(val string) val为形参,它的值受传递的实参来决定的。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理