Go:从defer返回

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

Go: returning from defer

问题

我想要在一个函数中,如果发生 panic 的话返回一个错误(在 Go 语言中):

func getReport(filename string) (rep report, err error) {
    rep.data = make(map[string]float64)

    defer func() {
        if r := recover(); r != nil {
            fmt.Println("Recovered in f", r)
            err, _ = r.(error)
            return nil, err
        }
    }()
    panic("Report format not recognized.")
    // 其他 getReport 函数的代码,可能会尝试越界访问一个切片
    ...
}

我似乎对 panic 和 defer 的概念有所误解。有人可以给我解释一下吗?

英文:

I want to return an error from a function if it panics (in Go):

func getReport(filename string) (rep report, err error) {
	rep.data = make(map[string]float64)

	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered in f", r)
			err, _ = r.(error)
            return nil, err
		}
	}()
	panic("Report format not recognized.")
    // rest of the getReport function, which can try to out-of-bound-access a slice
    ...
} 

I appear to have misunderstood the very concept of panic and defer. Can anybody enlighten me?

答案1

得分: 81

在延迟函数中,你可以修改返回的参数,但不能返回一个新的集合。所以只需对你的代码进行简单修改就可以使其正常工作。

你所写的代码还有另一个问题,即你使用了string类型进行恐慌处理,但在类型断言中却期望一个error类型。

以下是修复这两个问题的代码(Play链接):

defer func() {
	if r := recover(); r != nil {
		fmt.Println("Recovered in f", r)
		// 确定错误的具体类型并设置err
		switch x := r.(type) {
		case string:
			err = errors.New(x)
		case error:
			err = x
		default:
			err = errors.New("未知的恐慌")
		}
		// 使rep无效
		rep = nil
		// 返回修改后的err和rep
	}
}()
英文:

In a deferred function you can alter the returned parameters, but you can't return a new set. So a simple change to what you have will make it work.

There is another problem with what you wrote, namely that the you've paniced with a string but are expecting an error in your type assertion.

Here is a fix for both of those (Play)

defer func() {
	if r := recover(); r != nil {
		fmt.Println("Recovered in f", r)
		// find out exactly what the error was and set err
		switch x := r.(type) {
		case string:
			err = errors.New(x)
		case error:
			err = x
		default:
			err = errors.New("Unknown panic")
		}
		// invalidate rep
		rep = nil
		// return the modified err and rep
	}
}()

答案2

得分: 7

请看这个代码:

package main

import "fmt"

func iWillPanic() {
    panic("ops, panic")
}

func runner() (rtnValue string) {
    rtnValue = ""
    defer func() {
        if r := recover(); r != nil {
            // 在这里记录日志或者其他操作,不要什么都不记录
            rtnValue = "不要慌" // 修改返回值,然后返回
        }
    }()
    iWillPanic()
    return rtnValue
}

func main() {
    fmt.Println("返回值:", runner())
}

这段代码的功能是调用iWillPanic函数,该函数会引发一个恐慌(panic)。在runner函数中,使用defer语句和recover函数来捕获恐慌,并在恐慌发生时修改返回值。最后,在main函数中打印返回值。

注意:在恐慌发生时,程序会立即停止执行,并且不会执行后续的代码。

英文:

have a look at this

package main

import "fmt"

func iWillPanic() {
	panic("ops, panic")
}
func runner() (rtnValue string) {
	rtnValue := ""
	defer func() {
		if r := recover(); r != nil {
			// and your logs or something here, log nothing with panic is not a good idea
			rtnValue = "don't panic" // modify the return value, and it will return
		}
	}()
	iWillPanic()
	return rtnValue
}

func main() {
	fmt.Println("Return Value:", runner())
}

答案3

得分: 3

func TestReturnFromPanic(t *testing.T) {
fn := func(filename string) (rep string, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("在getReport中发生panic:%s", r)
}
}()
return filename[100:], nil
}
t.Log(fn(""))
}

命名返回参数err是关键。

https://play.golang.org/p/jpaCa9j2iAf

英文:
func TestReturnFromPanic(t *testing.T) {
   fn := func(filename string) (rep string, err error) {
	   defer func() {
		   if r := recover(); r != nil {
			   err = fmt.Errorf("panic in getReport %s", r)
		   }
	   }()
	   return filename[100:], nil
   }
   t.Log(fn(``))
}

The named return parameter err is the trick.

https://play.golang.org/p/jpaCa9j2iAf

huangapple
  • 本文由 发表于 2013年11月13日 00:31:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/19934641.html
匿名

发表评论

匿名网友

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

确定