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

Lar*_*tet 8 go deferred

调用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
}
Run Code Online (Sandbox Code Playgroud)

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

icz*_*cza 7

在第一个示例中,i是一个(传入)参数。在该return语句中,将评估返回值,并且延迟函数将在此之后运行,并且递增i该值不会影响返回值。

在第二个示例中,i是结果参数的名称。在该return语句中,您显式返回value i,然后将其分配给返回值i(这是一个无操作)。但是,允许延迟函数修改返回“变量”的值,如果这样做,则将对实际返回值产生影响。

如果再添加一个示例,这将变得更加清晰:

func c2() (i int) {
    defer func() { i++ }()
    return 2
}
Run Code Online (Sandbox Code Playgroud)

该函数将返回3,因为该return 2语句将分配2i该函数,然后deferred函数将对其递增,因此返回值将为3。在Go Playground上尝试一下。Spec中的相关部分:Return语句:

指定结果的“ return”语句在执行任何延迟函数之前会设置结果参数。

通常,如果函数(或方法)具有命名的结果参数,则返回值将始终是这些变量的值,但一定不要忘记,return语句可能会为这些结果参数分配新值,并且可以通过延迟来修改它们声明的功能return

Spec:Defer语句中提到了这一点:

例如,如果延迟函数是函数文字,并且周围函数已命名结果参数在文字范围内,则延迟函数可以在返回结果参数之前对其进行访问和修改。

博客文章Defer,Panic and Recover中也提到了这一点:

延迟函数可以读取并分配给返回函数的命名返回值。

有效的Go中:Recover

如果出现doParse紧急情况,恢复块会将返回值设置为— nil延迟函数可以修改命名的返回值。

请参阅相关问题:如何在出现恐慌的Go函数中返回值?