英文:
how defer statement works exactly
问题
我试着学习Go语言,并使用《Effective Go》作为教材。我在使用defer
语句时遇到了困难,看看下面的代码:
package main
import "fmt"
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() {
b()
}
输出结果是:
entering: b
in b
entering: a
in a
leaving: a
leaving: b
我知道,defer
语句会在函数中的return
语句之后执行。但是在这里,为什么"entering: b"是第一个输出?我期望"entering: b"是第一个输出!
英文:
i try to learn golang and use effective go as lecture. I stuck on capital defer, look at the following code
package main
import "fmt"
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
defer un(trace("a"))
fmt.Println("in a")
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
a()
}
func main() {
b()
}
as output i've got
entering: b
in b
entering: a
in a
leaving: a
leaving: b
I know, that defer statement will be execute after return statement in the function. But here, why entering: b is the first output? I am expected in b as the fist output!
答案1
得分: 8
根据http://golang.org/doc/effective_go.html#defer的说明:
延迟函数的参数(如果函数是一个方法,则包括接收者)在延迟执行时进行求值,而不是在调用执行时进行求值。除了避免函数执行过程中变量值的变化之外,这意味着一个延迟调用点可以延迟多个函数的执行。
因此,在你的情况下,defer函数的参数(trace("b"))首先进行求值。
英文:
According to http://golang.org/doc/effective_go.html#defer:
> The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the defer executes, not when the call executes. Besides avoiding worries about variables changing values as the function executes, this means that a single deferred call site can defer multiple function executions.
So argument of defer function (trace("b") in your case) evaluates first
答案2
得分: 2
简化后的代码如下:
package main
import "fmt"
func trace(s string) string {
fmt.Println("进入:", s)
return s
}
func un(s string) {
fmt.Println("离开:", s)
}
func b() {
defer un(trace("b"))
fmt.Println("在 b 中")
}
func main() {
b()
}
输出结果:
进入: b
在 b 中
离开: b
由于"延迟函数的参数在 defer
语句执行时被求值",所以在函数 b
中的语句
defer un(trace("b"))
可以等价地写为
{
unarg := trace("b")
defer un(unarg)
}
因此,等价的代码如下:
package main
import "fmt"
func trace(s string) string {
fmt.Println("进入:", s)
return s
}
func un(s string) {
fmt.Println("离开:", s)
}
func b() {
{
unarg := trace("b")
defer un(unarg)
}
fmt.Println("在 b 中")
}
func main() {
b()
}
输出结果:
进入: b
在 b 中
离开: b
同样地,对于完整的示例代码:
package main
import "fmt"
func trace(s string) string {
fmt.Println("进入:", s)
return s
}
func un(s string) {
fmt.Println("离开:", s)
}
func a() {
{
unarg := trace("a")
defer un(unarg)
}
fmt.Println("在 a 中")
}
func b() {
{
unarg := trace("b")
defer un(unarg)
}
fmt.Println("在 b 中")
a()
}
func main() {
b()
}
输出结果:
进入: b
在 b 中
进入: a
在 a 中
离开: a
离开: b
英文:
Simplifying,
package main
import "fmt"
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func b() {
defer un(trace("b"))
fmt.Println("in b")
}
func main() {
b()
}
Output:
entering: b
in b
leaving: b
Since "arguments to deferred functions are evaluated when the defer
executes", the
defer un(trace("b"))
statement in function b
is, using explicit scope, equivalent to
{
unarg := trace("b")
defer un(unarg)
}
Therefore, equivalently,
package main
import "fmt"
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func b() {
{
unarg := trace("b")
defer un(unarg)
}
fmt.Println("in b")
}
func main() {
b()
}
Output:
entering: b
in b
leaving: b
Equivalently, for your complete example,
package main
import "fmt"
func trace(s string) string {
fmt.Println("entering:", s)
return s
}
func un(s string) {
fmt.Println("leaving:", s)
}
func a() {
{
unarg := trace("a")
defer un(unarg)
}
fmt.Println("in a")
}
func b() {
{
unarg := trace("b")
defer un(unarg)
}
fmt.Println("in b")
a()
}
func main() {
b()
}
Output:
entering: b
in b
entering: a
in a
leaving: a
leaving: b
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论