Using named return variables to capture panics in Go

www.calhoun.io · · 513 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

This is going to be a short post inspired by Sean Kelly's tweet in November.

The goal is to just document and illustrate a situation where named return variables are necessary, so with that said let's just jump right in.

Imagine you are writing some code that uses a function that can panic, and for whatever reason (3rd party lib, backwards compatibility, etc) you can't change that function.

func pressButton() {  
  fmt.Println("I'm Mr. Meeseeks, look at me!!")
  // other stuff then happens, but if Jerry asks to 
  // remove 2 strokes from his golf game...
  panic("It's gettin' weird!")
}

You still need to use that function, but if it panics you want to capture the panic and return it as an error so you write some code like this:

func doStuff() error {  
  var err error
  // If there is a panic we need to recover in a deferred func
  defer func() {
    if r := recover(); r != nil {
      err = errors.New("the meeseeks went crazy!")
    }
  }()

  pressButton()
  return err
}

Run it on the Go Playground - https://play.golang.org/p/wzkjKGqFPL

Then you go run your code and... what's this? Your error is nil even when the code panics? That's not what we wanted!

Why does this happen?

While at first it looks like our code is returning the var err error that we create at the start of our function, the truth is our program never gets to that line of code. This means it never actually returns that specific err variable, and altering it inside of our deferred function ends up being pointless.

Adding a Println after the call to pressButton but before the return really helps illustrate this:

pressButton()  
// Nothing below here gets executed!
fmt.Println("we got here!")  
return err  

Run it on the Go Playground - https://play.golang.org/p/Vk0DYs20eB

How do we fix it?

To fix this issue, we can simply use a named return variable.

func doStuff() (err error) {  
    // If there is a panic we need to recover in a deferred func
    defer func() {
        if r := recover(); r != nil {
            err = errors.New("the meeseeks went crazy!")
        }
    }()

    pressButton()
    return err
}

Run it on the Go Playground - https://play.golang.org/p/bqGOroPjQJ

The resulting code looks very similar, but by naming our return variable when we declare the function our program will now return the err variable even if we never hit the return statement at the end of our doStuff function. Because of this minor difference, we can now alter the err variable inside of our deferred function and successfully capture the panic.


有疑问加站长微信联系(非本文作者)

本文来自:www.calhoun.io

感谢作者:www.calhoun.io

查看原文:Using named return variables to capture panics in Go

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

513 次点击  
加入收藏 微博
0 回复
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传