Go语言延迟调用

幸运草 2020年4月16日20:55:29前端框架评论阅读模式

defer是Go语言提供的关键字用来调度一个函数(被延期的函数),使其在执行defer的函数即将返回之前才被运行被延期执行的函数,它的参数(包括接受者)在defer执行的时候被求值的,而不是在调用执行的时候。也就是说被延期执行的函数的参数是按正常顺序被求值的。

defer常用来释放资源,如果有多个defer表达式,调用顺序类似于栈,越后面的defer表达式越先被调用。defer 函数调用的执行时机是外层函数设置返回值之后, 并且在即将返回之前。

defer应用

1、当defer被声明时,参数被实时解析

package main

import "fmt"

func oldboy() (str string) {
    str = "oldboy"
    defer fmt.Printf("defer : %sn", str)
    str = "老男孩IT教育,只培养技术精英。"
    return
}

func main() {
    oldboy()
}

运行结果:

defer : oldboy

通过运行结果,可以看到 defer 输出的值,就是定义时的值。

2、defer执行顺序为先进后出。

package main

import "fmt"

func test() {
    for i := 1; i < 4; i++ {
        defer fmt.Printf("defer%dn", i)
    }
}

func main() {
    test()
}

3、defer 可以读取有名返回值

package main

import (
    "fmt"
)

func test() (i int) {
    defer func() { i += 100 }()
    return 1
}

func main() {
    ret := test()
    fmt.Println(ret)
}

运行结果:

101

需要明确的是 defer 代码块的作用域仍然在函数之内,结合上面的函数也就是说,defer 的作用域仍然在 test() 函数之内。因此defer仍然可以读取 test() 函数内的变量。

当执行return 1 之后,i 的值是 1 。此时defer代码块开始执行 i += 100操作。 因此最后输出 101。

defer陷阱

1、defer 与 closure

package main

import (
    "errors"
    "fmt"
)

func test(x, y int) (z int, err error) {
    defer fmt.Printf("first defer err %vn", err)
    defer func(err error) { fmt.Printf("second defer err %vn", err) }(err)
    defer func() { fmt.Printf("third defer err %vn", err) }()
    if y == 0 {
        err = errors.New("divided by zero!")
        return
    }

    z = x / y
    return
}

func main() {
    test(2, 0)
}

运行结果:

third defer err divided by zero!
second defer err <nil>
first defer err <nil>

解释:如果 defer 后面跟的不是一个 closure 最后执行的时候我们得到的并不是最新的值。

2、defer 与 return

package main

import "fmt"

func test() (i int) {

    i = 0
    defer func() {
        fmt.Println(i)
    }()

    return 2
}

func main() {
    test()
}

输出结果:

2

解释:在有具名返回值的函数中(这里具名返回值为 i),执行 return 2 的时候实际上已经将 i 的值重新赋值为 2。所以defer closure 输出结果为 2 而不是 1。

3、defer nil 函数

package main

import (
    "fmt"
)

func test() {
    var run func() = nil
    defer run()
    fmt.Println("runs")
}

func main() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Println(err)
        }
    }()
    test()
}

输出结果:

runs
runtime error: invalid memory address or nil pointer dereference

解释:名为 test 的函数一直运行至结束,然后 defer 函数会被执行且会因为值为 nil 而产生 panic 异常。然而值得注意的是,run() 的声明是没有问题,因为在test函数运行完成后它才会被调用。

特别声明:以上文章内容仅代表作者本人观点,不代表变化吧观点或立场。如有关于作品内容、版权或其它问题请于作品发表后的30日内与变化吧联系。

  • 赞助本站
  • 微信扫一扫
  • weinxin
  • 加入Q群
  • QQ扫一扫
  • weinxin
幸运草
Go语言接口规则 前端框架

Go语言接口规则

Go语言接口规则 接口是一个或多个方法签名的集合。任何类型的方法集中只要拥有该接口对应的全部方法签名。就表示它 "实现" 了该接口,无须在该类型上显式声明实现了哪个接口。对应方法,是指有相同名称、参数...
Go语言中处理 HTTP 服务器 前端框架

Go语言中处理 HTTP 服务器

1 概述 包 net/http 提供了HTTP服务器端和客户端的实现。本文说明关于服务器端的部分。 快速开始: package main import (   "log"   "net/http" )...

发表评论