为什么我在下面的golang代码示例中使用defer得到和1

yqkkidmi  于 2023-09-28  发布在  Go
关注(0)|答案(1)|浏览(93)

对于以两种不同方式声明的变量,调用defer会产生不同的结果

package main

import (
    "fmt"
)

func c(i int) int {
    defer func() { i++ }()
    return i
}

func c1() (i int) {
    defer func() { i++ }()
    return i
}

func c2() (i int) {
    defer func() { i++ }()
    return 2
}

func main() {
    fmt.Println(c(0)) // Prints 0
    fmt.Println(c1()) // Prints 1
    fmt.Println(c2()) // Prints 3 Thank you icza
}

https://play.golang.org/p/gfnnCZ--DkH

8yparm6h

8yparm6h1#

在第一个例子中,i是一个(传入的)参数。在return语句中,返回值被计算,在此之后,延迟函数运行,并且在中递增i对返回值没有影响。
在第二个示例中,i是结果参数的名称。在return语句中,显式返回值i,然后将其赋给返回值i(这是一个无操作)。但是延迟函数被允许修改返回“变量”的值,如果它们这样做了,那将对实际返回值产生影响。
如果我们再加上一个例子,这一点就变得更加清楚了:

func c2() (i int) {
    defer func() { i++ }()
    return 2
}

这个函数将返回3,因为return 2语句将把2赋值给i,然后延迟函数将递增它,因此返回值将是3。在Go Playground上试试这个。规范中的相关部分:返回语句:
指定结果的“return”语句在执行任何延迟函数之前设置结果参数。
一般来说,如果一个函数(或方法)有命名的结果参数,返回值将始终是这些变量的值,但不要忘记,return语句可能会为这些结果参数分配新值,并且它们可能会被延迟函数 * 在 * return语句之后修改。
这在规范中提到:延迟语句
例如,如果延迟函数是函数文字并且周围函数具有在文字内的范围内的命名结果参数,则延迟函数可以在结果参数被返回之前访问和修改结果参数。
在博客文章Defer, Panic and Recover中也提到:
延迟函数可以读取返回函数的命名返回值并将其赋给返回函数。

Effective Go:恢复

如果doParse死机,恢复块将返回值设置为nil-延迟函数可以修改命名的返回值。
参见相关问题:如何在Go函数中返回一个恐慌的值?

相关问题