Go defer 去掉闭包函数,靠谱吗?

发布时间 2023-07-25 09:09:15作者: 善為

在Go中使用defer时,如果defer语句包含了一个闭包函数,需要特别小心。因为defer语句会在函数返回时执行,而闭包函数可能会捕获外部变量,导致意想不到的结果。

在Go中,defer语句中的闭包函数捕获的是变量的地址,而不是变量的值。如果闭包函数在defer执行时才被调用,可能会导致捕获的变量值在调用时已经发生了变化。

下面是一个示例代码,演示在defer中使用闭包函数的问题:

package main

import "fmt"

func main() {
    num := 10

    defer func() {
        fmt.Println("Deferred:", num) // 会打印 "Deferred: 20"
    }()

    num = 20
    fmt.Println("Original:", num) // 打印 "Original: 20"
}

  

在上述示例中,我们在defer语句中使用了一个闭包函数,该闭包函数捕获了外部变量num的地址。在函数执行过程中,num的值被修改为20,然后在函数返回时,defer语句执行,闭包函数打印的是捕获的num的地址对应的值,即20。

如果我们想避免这种情况,可以在defer语句中调用一个普通函数,而不是使用闭包函数,以确保在调用defer时已经确定了变量的值。

下面是修复后的示例代码:

 
package main

import "fmt"

func deferredFunc(num int) {
    fmt.Println("Deferred:", num)
}

func main() {
    num := 10

    defer deferredFunc(num)

    num = 20
    fmt.Println("Original:", num) // 打印 "Original: 20"
}

  

在上述示例中,我们使用了一个普通函数deferredFunc来替代闭包函数,在defer语句中调用这个函数。这样,当defer执行时,参数num的值已经确定为10,并不会受到后续的修改影响。

总的来说,为了避免在defer中使用闭包函数可能带来的问题,最好使用普通函数,并确保在defer执行时已经确定了变量的值。这样能够更加安全和可靠地使用defer语句。