首页 > 编程笔记 > Go语言笔记 阅读:2

Go语言defer语句的用法(附带实例)

在 Go 语言中,使用 defer 语句可以延迟处理其后定义的函数或语句。如果在某个函数中使用 defer 语句,则紧跟在该语句后面的程序在 defer 所在的函数即将返回时执行。

Go语言多个defer语句的执行顺序

在函数中使用多个 defer 语句时,当该函数即将返回时,多个延迟处理的语句将按 defer 语句的逆序执行。也就是说,先使用 defer 的语句后执行,后使用 defer 的语句先执行。

代码如下:
package main

import (
    "fmt"
)

func main() {
    fmt.Println("程序开始")
    defer fmt.Println(1)    // 最后调用
    defer fmt.Println(2)    // 其次调用
    defer fmt.Println(3)    // 最先调用
    fmt.Println("程序结束")
}
运行结果如下:

程序开始
程序结束
3
2
1

由运行结果可以看出,延迟调用是在defer语句所在函数结束时进行的,并且最后使用 defer 语句先进行调用。

Go语言延迟函数的参数

defer 语句中的内容虽然在函数结束时执行,但如果延迟函数有参数则先计算参数的值。代码如下:
package main

import (
    "fmt"
)

func first(num int) int { // 定义first()函数
    fmt.Println("我是 first")
    return num + 10
}

func second(num int) int { // 定义second()函数
    fmt.Println("我是 second")
    return num + 20
}

func third(num int) int { // 定义third()函数
    fmt.Println("我是 third")
    return num + 30
}

func main() {
    num := 10
    fmt.Println("程序开始")
    defer fmt.Println(second(num))
    num = 20
    defer fmt.Println(third(num))
    defer fmt.Println(first(num))
    fmt.Println("程序结束")
}
运行结果如下:

程序开始
我是 second
我是 third
程序结束
50
30
我是 first

上述代码分析如下:
1) 共有 3 个自定义函数 first()、second() 和 third(),使用 defer 语句延迟调用函数 first()。second() 和 third() 函数是延迟函数的参数,正常输出“我是second”和“我是third”。second() 和 third() 两个函数的返回值和“我是first”在函数结束时输出。

2) 在调用 second() 函数时,传入的参数 num 的值是 10,后面对 num 值的修改不影响 second() 函数的返回值。在调用 third() 函数时,参数 num 的值修改为 20,所以在调用两个函数时,实参的值是不同的。

Go语言匿名函数的延迟调用

使用 defer 语句延迟调用的函数可以是匿名函数,这种情况的应用比较广泛。代码如下:
package main

import (
    "fmt"
)

func main() {
    fmt.Println("程序开始")
    defer func() {
        fmt.Println("延迟调用")
    }()
    fmt.Println("程序结束")
}
运行结果如下:

程序开始
程序结束
延迟调用

在函数中使用 defer 语句延迟调用匿名函数时,如果该函数有返回值,则可能有两种情况,一种是返回值未设置变量名,另一种是为返回值设置变量名。

1) 返回值未设置变量名

如果使用 defer 语句的函数有返回值,而且该返回值未设置变量名,那么在执行 defer 语句时不能修改返回值。代码如下:
package main

import (
    "fmt"
)

func test() int {
    var i int
    defer func() {
        i++
        fmt.Println("defer2:", i)
    }()
    defer func() {
        i++
        fmt.Println("defer1:", i)
    }()
    return i
}

func main() {
    fmt.Println("return:", test())
}
运行结果如下:

defer1: 1
defer2: 2
return: 0

在上述代码中,test() 函数的返回值未设置变量名,函数返回的是函数内声明的变量 i 的值,这样,在执行 defer 语句时不能修改 test() 函数的返回值,所以调用 test() 函数得到的返回值是变量 i 的默认值 0。

2) 返回值设置变量名

如果使用 defer 语句的函数有返回值,并为该返回值设置变量名,那么在执行 defer 语句时可以修改返回值。代码如下:
package main

import (
    "fmt"
)

func test() (i int) {
    defer func() {
        i++
        fmt.Println("defer2:", i)
    }()
    defer func() {
        i++
        fmt.Println("defer1:", i)
    }()
    return i
}

func main() {
    fmt.Println("return:", test())
}
运行结果如下:

defer1: 1
defer2: 2
return: 2

在上述代码中,test() 函数的返回值设置为变量 i,这样,在执行 defer 语句时可以修改 test() 函数的返回值,所以调用 test() 函数的返回值是执行两次 i++ 后的结果,也就是 2。

相关文章