为什么我在以下带有延迟的 golang 代码示例中得到 0 和 1

Why I get 0 and 1 in the following golang code example with defer

对于以两种不同方式声明的变量,调用 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

在第一个示例中,i 是一个(传入)参数。在 return 语句中计算 return 值,延迟函数在此之后运行,递增 i 对 return 值没有影响。

在第二个例子中,i是结果参数的名称。在 return 语句中,您显式 return 值 i,然后将其分配给 return 值 i(这是一个空操作)。但是允许延迟函数修改 return "variables" 的值,如果它们这样做,将对实际的 returned 值产生影响。

如果我们添加另一个示例,这将变得更加清楚:

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

这个函数会return3,因为return 2语句会将2赋值给i,然后延迟函数会递增这个,并且所以 return 值将是 3。在 Go Playground. Relevant part from the Spec: Return statements:

上试试这个

A "return" statement that specifies results sets the result parameters before any deferred functions are executed.

一般来说,如果一个函数(或方法)有命名的结果参数,return 值将永远是这些变量的值,但一定不要忘记 return 语句可以赋值这些结果参数的新值,它们可以通过延迟函数修改 一个 return 语句后。

这个在Spec: Defer statements中提到:

For instance, if the deferred function is a function literal and the surrounding function has named result parameters that are in scope within the literal, the deferred function may access and modify the result parameters before they are returned.

博客里也提到了post Defer, Panic and Recover:

Deferred functions may read and assign to the returning function's named return values.

还有 Effective Go: Recover:

If doParse panics, the recovery block will set the return value to nil—deferred functions can modify named return values.

参见相关问题: