大吃一惊:命名返回值影响到defer

113 阅读2分钟

一、defer 关键字

在 Go 语言中,defer 是一个用于延迟执行函数的关键字。当我们在一个函数中使用 defer 关键字,紧跟着一个函数调用时,这个函数调用会被推迟到包含它的函数执行完成之前执行。这在处理资源释放、解锁或者执行清理操作等场景中非常有用。下面是一个简单的示例:

package main

import "fmt"

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

输出结果:

start
end
deferred

从输出结果可以看出,虽然 "deferred" 这个字符串的打印语句在 "end" 之前,但是由于使用了 defer 关键字,它的执行被推迟到了 main 函数执行完成之前。

二、defer 与返回值

接下来,我们将探讨 defer 与函数返回值之间的关系。在 Go 语言中,函数可以有两种返回值:匿名返回值和命名返回值。

2.1 匿名返回值

匿名返回值是指在函数签名中没有为返回值指定名称的情况。在这种情况下,我们需要在函数体内显式地返回值。下面是一个简单的示例:

package main

import "fmt"

func anonymousReturn() int {
    x := 10
    defer func() {
        x += 5
    }()
    return x
}

func main() {
    fmt.Println(anonymousReturn()) // 输出:10
}

在这个示例中,尽管我们在 defer 函数中修改了 x 的值,但是返回值仍然是 10。这是因为在匿名返回值的情况下,返回值在执行 return 语句时就已经确定了,defer 函数对 x 的修改不会影响到返回值。

2.2 命名返回值

命名返回值是指在函数签名中为返回值指定了名称的情况。在这种情况下,我们可以在函数体内直接修改返回值,而无需显式地返回它。下面是一个简单的示例:

package main

import "fmt"

func namedReturn() (x int) {
    x = 10
    defer func() {
        x += 5
    }()
    return
}

func main() {
    fmt.Println(namedReturn()) // 输出:15
}

在这个示例中,我们在 defer 函数中修改了 x 的值,返回值也随之改变。这是因为在命名返回值的情况下,返回值在执行 return 语句时并没有确定,defer 函数对 x 的修改会影响到返回值。