为什么正常的退货会隐藏命名的退货正确提供给呼叫者的恐慌? [英] Why can a normal return hide a panic that a named return correctly provides to the caller?
问题描述
package main
import (
"fmt"
"log"
)
func catch(err *error) {
if r := recover(); r != nil {
*err = fmt.Errorf("recovered panic: %v", r)
}
}
func panicIf42(n int) {
if n == 42 {
panic("42!")
}
}
func NormalReturns(n int) error {
var err error
defer catch(&err)
panicIf42(n)
return err
}
func NamedReturns(n int) (err error) {
defer catch(&err)
panicIf42(n)
return
}
func main() {
err := NamedReturns(42)
log.Printf("NamedReturns error: %v", err)
err = NormalReturns(42)
log.Printf("NormalReturns error: %v", err)
}
输出:
2009/11/10 23:00:00 NamedReturns error: recovered panic: 42!
2009/11/10 23:00:00 NormalReturns error: <nil>
NormalReturns返回nil错误,但我希望NamedReturns和NormalReturns都返回非nil错误.
NormalReturns returns a nil error, but I would expect both NamedReturns and NormalReturns to return a non-nil error.
我认为命名的returns只是一种代码可读性功能,可以为您声明和初始化return,但似乎还有更多功能.我想念什么?
I thought named returns was just a code readability feature that declares and initializes returns for you, but it seems there's more to it. What am I missing?
推荐答案
我认为命名的returns只是一种代码可读性功能,可以为您声明和初始化return,但似乎还有更多功能.我想念什么?
I thought named returns was just a code readability feature that declares and initializes returns for you, but it seems there's more to it. What am I missing?
如果命名结果参数,则返回给调用方时它们的实际值将确定返回的值.这意味着您可以像其他局部变量一样更改它们的值,并且如果return
语句的表达式列表为空,则将使用它们的最后分配值.同样,如果有延迟函数,它们可以在return
语句之后的 和之前的函数返回其调用方的过程中修改命名结果参数的值,这些修改将被保存.它也允许在出现紧急情况时修改返回值,请参见
If you name the result parameters, their actual value at the time of returning to the caller will determine the returned values. Meaning you can change their values like other local variables, and if the expression list of the return
statement is empty, their last assigned values will be used. Also if there are deferred functions, they can modify the values of the named result parameters after the return
statement and before the function returns to its caller, and those modifications will be preserved. It also allows to modify return values in case of a panic, see How to return a value in a Go function that panics?
无论如何声明[返回值],所有结果值都将初始化为零值表示其在输入函数时的类型.指定结果的"return"语句在执行任何延迟函数之前会设置结果参数.
Regardless of how they [the return values] are declared, all the result values are initialized to the zero values for their type upon entry to the function. A "return" statement that specifies results sets the result parameters before any deferred functions are executed.
例如,如果延迟函数是函数文字,并且周围函数具有命名结果参数,延迟函数可以在访问和修改结果参数之前对其进行访问和修改返回.
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.
在NormalReturns()
中:返回值被初始化为其零值(对于所有接口类型,包括内置
In NormalReturns()
: The return value is initialized to its zero value (which is nil
for all interface types, including the builtin error
type), and since the return
statement is not reached (due to a panic in panicIf42()
), it will stay nil
. It doesn't matter if the local variable err
is changed, that is not the result variable. It's just an ordinary variable. It will have no effect on the value returned
通常,如果一个函数没有命名结果变量,并且该函数没有到达return
语句(例如由于紧急情况),则它的返回值不能为零(与零不同).结果类型的值.
In general, if a function does not have named result variables, and if this function does not reach a return
statement (e.g. due to a panic), it cannot have return values other than (meaning different from) the zero values of the result types.
在NamedReturns()
中,延迟的catch()
将修改命名结果变量err
.更改是保留的":函数结束时将返回任何命名结果变量所保存的内容(如果存在,则在调用延迟函数之后发生).因此,即使这里也未到达return
语句,catch()
函数也会更改err
结果变量,并且分配给它的任何内容都将用作返回的值.
In NamedReturns()
the deferred catch()
will modify the named result variable err
. The changes are "preserved": whatever the named result variables hold will be returned when the function ends (which happens after calling deferred functions, if there are any). So even though the return
statement is not reached here either, the catch()
function changes the err
result variable, and whatever is assigned to it will be used as the value returned.
有关该主题的更多信息:
More on the topic:
延迟的函数可以读取并分配给返回函数的命名返回值.
Deferred functions may read and assign to the returning function's named return values.
如果
doParse
出现紧急情况,恢复块会将返回值设置为nil
-延迟函数可以修改命名的返回值.
If
doParse
panics, the recovery block will set the return value tonil
—deferred functions can modify named return values.
这篇关于为什么正常的退货会隐藏命名的退货正确提供给呼叫者的恐慌?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!