调用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)
在第一个示例中,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语句将分配2给i该函数,然后deferred函数将对其递增,因此返回值将为3。在Go Playground上尝试一下。Spec中的相关部分:Return语句:
指定结果的“ return”语句在执行任何延迟函数之前会设置结果参数。
通常,如果函数(或方法)具有命名的结果参数,则返回值将始终是这些变量的值,但一定不要忘记,return语句可能会为这些结果参数分配新值,并且可以通过延迟来修改它们声明后的功能return。
在Spec:Defer语句中提到了这一点:
例如,如果延迟函数是函数文字,并且周围函数已命名结果参数在文字范围内,则延迟函数可以在返回结果参数之前对其进行访问和修改。
博客文章Defer,Panic and Recover中也提到了这一点:
延迟函数可以读取并分配给返回函数的命名返回值。
如果出现
doParse紧急情况,恢复块会将返回值设置为—nil延迟函数可以修改命名的返回值。
请参阅相关问题:如何在出现恐慌的Go函数中返回值?