当前位置: 首页 > 知识库问答 >
问题:

为什么go panic用局部变量恢复返回值不起作用?

仲孙俊贤
2023-03-14

此panic恢复代码使用命名的返回值。

func main() {
    result, err := foo()
    fmt.Println("result:", result)
    if err != nil {
        fmt.Println("err:", err)
    }
}

func foo() (result int, err error) {
    defer func() {
        if e := recover(); e != nil {
            result = -1
            err = errors.New(e.(string))
        }
    }()
    bar()

    result = 100
    err = nil
    return
}

func bar() {
    panic("panic happened")
}

输出

result: -1
err: panic happened
func main() {
    result, err := foo()
    fmt.Println("result:", result)
    if err != nil {
        fmt.Println("err:", err)
    }
}

func foo() (int, error) {
    var result int
    var err error
    defer func() {
        if e := recover(); e != nil {
            result = -1
            err = errors.New(e.(string))
        }
    }()
    bar()

    result = 100
    err = nil
    return result, err
}

func bar() {
    panic("panic happened")
}
result: 0

共有1个答案

顾穆冉
2023-03-14

spec:Return语句详细说明了以下内容:

从具有结果类型的函数返回值有三种方法:

  1. 返回值可以在“return”语句中显式列出。每个表达式必须是单值的,并且可赋值给函数结果类型的相应元素。
  2. “return”语句中的表达式列表可能是对多值函数的单个调用。其效果是,从该函数返回的每个值都被赋给了一个临时变量,该变量的类型与相应值的类型相同,后面跟着一个列出这些变量的“return”语句,在这一点上,应用了前面案例的规则。
  3. 如果函数的结果类型为其结果参数指定了名称,则表达式列表可能为空。结果参数充当普通的局部变量,函数可以根据需要为它们赋值。“return”语句返回这些变量的值。

因此,基本上,如果使用显式列出返回值的return语句,将使用这些返回值,而不管结果参数是否命名。

如果结果参数被命名,它们就充当普通的局部变量:您可以读写它们。如果指定了结果参数,则可以使用“naked”return语句,而不列出要返回的值。如果这样做,那么实际返回值将是(命名的)结果参数的值。如果函数由于panicing和recovery而没有到达return语句,那么同样的情况也适用:一旦延迟函数运行,实际返回值将是命名结果参数的值(延迟函数可以更改这些参数,并且“有权”返回什么)。

如果您不使用命名的结果参数,而是声明局部变量,它们在这种方式上并不特殊:当函数返回时,这些参数不会“自动”用作结果值(就像它们被命名为结果参数而不是局部变量时一样)。因此,如果在延迟函数中更改它们,则不会对返回的实际值产生任何影响。事实上,如果您不使用命名的结果参数并且您的函数panics和recover,您就不能指定返回值,它们将是结果类型的零值。这就是为什么您会看到结果:0(0int)的零值,并且没有错误(因为error是接口类型,接口类型的零值是nil,如果是nil,则不会打印错误)。

参见相关内容:如何在Go函数中返回一个值?

 类似资料:
  • 问题内容: 当我通过redis EVAL运行此代码时,它不会返回任何结果。知道为什么这行不通吗? bug.lua 如果我初始化表,则仅打印该值。 问题答案: 如果您参考Redis 文档 ,则可以看到Redis将Lua表转换为Redis回复所使用的规则: Lua表(数组)-> Redis多批量回复( 如果有的话,将被截断为Lua数组中的第一个nil ) Lua表带有单个ok字段-> Redis状态回

  • 问题内容: Java的设计者是否有任何理由认为不应为局部变量提供默认值?认真地讲,如果实例变量可以被赋予默认值,那为什么我们不能对局部变量做同样的事情呢? 问题答案: 声明局部变量主要是为了进行一些计算。因此,程序员决定设置变量的值,并且不应采用默认值。如果程序员错误地没有初始化局部变量并且使用默认值,则输出可能是一些意外值。因此,在使用局部变量的情况下,编译器将要求程序员在访问变量之前使用一些值

  • 上面所有的变量都有标题中的警告。你能告诉我为什么会这样吗?

  • 我不太明白用函数返回值和只在函数中操作全局变量之间的区别。我读过的大多数指南和书籍似乎都鼓励使用前者,而不是后者。 例如,这里有两个Python代码块(据我所知)做同样的事情: 当然,第一个例子看起来更简洁明了,但是两者得到了相同的结果;他们得到了一个值为6的变量。那么有理由使用第一个例子而不是第二个例子吗?

  • 问题内容: 考虑以下JavaScript: 上面的代码片段中的方法返回的是正确的值,在这种情况下。但是,该方法返回。大多数其他语言不是这种情况。 但是,以下函数是正确的,并返回正确的值。 如果语法错误,它应该发出一些编译器错误,但不会。为什么会这样? 问题答案: 从技术上讲,JavaScript中的半冒号是可选的。但是实际上 , 如果它认为缺少某些换行符, 它只会为您插入它们 。但是它为您带来的决

  • 主要内容:Python局部变量,Python全局变量,获取指定作用域范围中的变量所谓 作用域(Scope),就是变量的有效范围,就是变量可以在哪个范围以内使用。有些变量可以在整段代码的任意位置使用,有些变量只能在函数内部使用,有些变量只能在 for 循环内部使用。 变量的作用域由变量的定义位置决定,在不同位置定义的变量,它的作用域是不一样的。本节我们只讲解两种变量, 局部变量和 全局变量。 Python局部变量 在函数内部定义的变量,它的作用域也仅限于函数内部,出了函数就不能