Why defer behaves differently with variables defined in the surrounding function than named results?

huangapple go评论76阅读模式
英文:

Why defer behaves differently with variables defined in the surrounding function than named results?

问题

下面的程序返回:

<nil>
hello

我期望两者都返回"hello",但事实并非如此。我在语言规范的示例中找到了这种行为的说明。

例如,如果延迟函数是一个函数字面量,并且周围的函数具有在字面量内部范围内的命名结果参数,则延迟函数可以在返回之前访问和修改结果参数。

我的问题是:为什么延迟函数在处理周围函数中定义的变量时与命名结果不同?它不只是在周围函数返回之前执行的闭包吗?

package main

import (
	"errors"
	"fmt"
)

func main() {

	fmt.Println(up())
	fmt.Println(up2())

}

func up() error {
	var err error
	defer func() {
		err = errors.New("hello")
	}()
	return err
}

func up2() (err error) {
	defer func() {
		err = errors.New("hello")
	}()
	return err
}

func up3() error {
	var err error
	fn := func() {
		err = errors.New("hello")
	}
	fn()
	return err
}
英文:

The program below returns

&lt;nil&gt;
hello

I expected both to return "hello" but it's not the case. I've found that the behaviour is given as example in the language spec.

> 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.

My question is: why does defer works differently with variables defined in the surrounding function than with named results? Isn't it just a closure executed before the surrounding function returns?

package main

import (
	&quot;errors&quot;
	&quot;fmt&quot;
)

func main() {

	fmt.Println(up())
	fmt.Println(up2())

}

func up() error {
	var err error
	defer func() {
		err = errors.New(&quot;hello&quot;)
	}()
	return err
}

func up2() (err error) {
	defer func() {
		err = errors.New(&quot;hello&quot;)
	}()
	return err
}

func up3() error {
	var err error
	fn := func() {
		err = errors.New(&quot;hello&quot;)
	}
	fn()
	return err
}

答案1

得分: 5

规范中提到:

> "defer"语句会调用一个函数,该函数的执行被延迟到包围它的函数返回的时刻,无论是因为包围它的函数执行了一个return语句,到达了函数体的末尾,还是因为相应的goroutine正在发生panic。

一个关键点是,延迟函数在return语句执行之后执行。

规范还提到:

> 函数F中的"return"语句终止了F的执行,并可选择提供一个或多个结果值。F延迟的任何函数都会在F返回给其调用者之前执行。

函数up返回nil,因为延迟函数在return语句提供函数结果之后设置了err

函数up2覆盖了return语句设置的结果值。

英文:

The spec says:

> A "defer" statement invokes a function whose execution is deferred to the moment the surrounding function returns, either because the surrounding function executed a return statement, reached the end of its function body, or because the corresponding goroutine is panicking.

A key point is that the deferred function is executed after the return statement is executed.

The spec also says:

> A "return" statement in a function F terminates the execution of F, and optionally provides one or more result values. Any functions deferred by F are executed before F returns to its caller.

The function up returns nil because the deferred function sets err after the return statement provides the function result.

The function up2 overwrites the result value set by the return statement.

huangapple
  • 本文由 发表于 2017年4月19日 01:39:05
  • 转载请务必保留本文链接:https://go.coder-hub.com/43478834.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定