跳到主要内容

Go 命名返回值和非命名返回值在使用 defer 时的不同表现

· 阅读需 2 分钟
素明诚
Full stack development

使用命名返回值

通过 defer 修改这个返回值。

package main

import "fmt"

func modifyWithNamedReturn() (result int) {
defer func() {
result += 5 // 修改命名返回值
}()

return 10 // 初始设置返回值为 10
}

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

解释

  • 这个函数 modifyWithNamedReturn 中有一个命名返回值 result
  • 函数返回时,首先设置 result10
  • 在函数实际返回前,defer 语句执行,将 result 的值增加 5
  • 因此,虽然 return 语句最初将返回值设置为 10defer 修改后,最终返回值变为 15

使用非命名返回值

defer 如何无法修改返回值。

package main

import "fmt"

func modifyWithoutNamedReturn() int {
var result int

defer func() {
result += 5 // 尝试修改,但不影响返回值
}()
result = 10 // 设置 result 的值

return result // 返回 result 的值
}

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

解释

  • 函数 modifyWithoutNamedReturn 返回一个非命名返回值。
  • result 被设置为 10,并准备用作返回值。
  • 尽管 defer 函数将 result 增加了 5,但这种修改发生在返回值被确定(已复制)后,因此对实际返回给调用者的值没有影响。
  • 最终输出为 10,展示了即使 defer 修改了局部变量 result,也不会改变返回值。

defer 使用总结

defer 在命名返回值情况下可以修改最终的返回值,因为命名返回值的作用域延伸至整个函数,包括 defer 执行的时间。而在非命名返回值的情况下,return 语句实际上是将值复制到返回位置,此后的 defer 修改不再影响已经设置的返回值。

简单点可以这样理解,命名返回值,说明返回值很重要,要都处理完再返回~