我可以使用指向“错误”的指针来捕获返回错误吗?

I am writing some transaction begin/commit/rollback functions, and I want to pair the block to prevent forgot commit

I write like this:


func (foo *Foo) Bar() (err error) {

  foo.Begin()
  defer foo.End(&err)

  //some business code

  return
}

func (foo *Foo) End(eptr *error) {
  // if recover
  if r := recover(); r != nil {
    debug.PrintStack()
    *eptr = r.(error)
  }

  var err = *eptr
  if err != nil {
    foo.Rollback()
  } else {
    foo.Commit()
  }
}

It works, but it uses the "pointer to interface", I cannot find the specifications about pointer to interface.

So, I am not sure this code is OK enough. Could you give some suggestions?


thanks to teyzer and Corey Ogburn, this is my fixed solution:


func (foo *Foo) Bar() (err error) {

  foo.Begin()
  defer func() { foo.End(err) }()
  defer func() {
   if r := recover(); r != nil {
      debug.PrintStack()
      err = makeError(r)
   }
  } ()

  //some business code

  return
}

func (foo *Foo) End(err error) {  
  if err != nil {
    foo.Rollback()
  } else {
    foo.Commit()
  }
}

The usual approach is to use recover() to catch any panics. What you have is very similar to that approach. Check out the Go wiki about Panic and Recover

func (foo *Foo) Bar() (err error) {

  foo.Begin()
  defer foo.End()

  //some business code
  err = fmt.Errorf("oh no, an error!") // set error so that Bar returns it even though it's caught
  panic(err)

  return
}

func (foo *Foo) End() {
  err := recover()
  if err != nil {
    foo.Rollback()
  } else {
    foo.Commit()
  }
}

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

The parameters to a deferred function are immediately evaluated when defer is reached. Thats why you have to use a pointer if you defer End itself.

Instead you can use a closure. Your Bar() function would look like this:


func (foo *Foo) Bar() (err error) {
    foo.Begin()
    defer func() { foo.End(err) }()
    //some business code
    return
}

Here the value of err is evaluated once the deferred closure is executed.

If you're not stuck on using error returns, using panic and recover is the more idiomatic way in Go to handle such errors that require a rollback (like Corey Ogburn recommended).