Могу ли я использовать указатель на «error», чтобы перехватить ошибку? - PullRequest
0 голосов
/ 30 мая 2019

Я пишу некоторые функции начала / принятия / отката транзакции, и я хочу связать блок, чтобы предотвратить забытую фиксацию

Я пишу так:


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()
  }
}

Работает, но использует "указатель на интерфейс", я не могу найти спецификации указателя на интерфейс.

Итак, я не уверен, что этот код достаточно хорош. Не могли бы вы дать несколько предложений?


благодаря Тейзеру и Кори Огберну, это мое исправленное решение:


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()
  }
}

Ответы [ 2 ]

3 голосов
/ 30 мая 2019

Параметры для отложенной функции немедленно оцениваются при достижении defer.Вот почему вы должны использовать указатель, если вы откладываете End.

Вместо этого вы можете использовать замыкание.Ваша функция Bar() будет выглядеть следующим образом:


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

Здесь значение err вычисляется после выполнения отложенного закрытия.

Если вы не застряли с использованием ошибкивозврат, использование паники и восстановления - более идиоматичный способ в Go обрабатывать такие ошибки, которые требуют отката (как рекомендуется Corey Ogburn).

0 голосов
/ 30 мая 2019

Обычный подход заключается в использовании recover() для перехвата любых panic с. То, что у вас есть, очень похоже на этот подход. Ознакомьтесь с Go wiki о панике и выздоровлении

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...