Go语言 一种不使用最新的err值写入long defer的方法?

jrcvhitl  于 2023-10-14  发布在  Go
关注(0)|答案(1)|浏览(98)

我有一个有效的代码。

  1. func (r *repoPG) WithTransaction(txFunc func() error) (err error) {
  2. tx := db.NewTx()
  3. defer func() {
  4. if r := recover(); r != nil {
  5. err = fmt.Errorf("panic: %v", r)
  6. tx.Rollback()
  7. } else if err != nil {
  8. tx.Rollback()
  9. } else {
  10. tx.Commit()
  11. }
  12. }()
  13. err = txFunc()
  14. return
  15. }

我想avod每次都写那么长的defer,所以我试着写一个这样的函数:

  1. func TxDefer(tx, err) {
  2. if r := recover(); r != nil {
  3. err = fmt.Errorf("panic: %v", r)
  4. tx.Rollback()
  5. } else if err != nil {
  6. tx.Rollback()
  7. } else {
  8. tx.Commit()
  9. }
  10. }

使用它就像:

  1. func (r *repoPG) WithTransaction(txFunc func() error) (err error) {
  2. tx := db.NewTx()
  3. defer TxDefer(tx, err)
  4. err = txFunc()
  5. return
  6. }

但这是错误的,因为err总是原始的,而不是txFunc()的结果,对吗?
我该怎么办?

vdzxcuhz

vdzxcuhz1#

将错误的地址传递给函数。这允许函数访问调用方变量的当前值。它还允许函数设置变量。
回滚和提交返回错误。这些错误应该返回给调用方。

  1. func TxDefer(tx Transaction, perr *error) {
  2. if r := recover(); r != nil {
  3. *perr = fmt.Errorf("panic: %v", r)
  4. tx.Rollback()
  5. } else if *perr != nil {
  6. err = tx.Rollback()
  7. if err != nil {
  8. // replace original error with rollback error
  9. *perr = err
  10. }
  11. } else {
  12. *perr = tx.Commit()
  13. }
  14. }

这样使用:

  1. func (r *repoPG) WithTransaction(txFunc func() error) (err error) {
  2. tx := db.NewTx()
  3. defer TxDefer(tx, &err)
  4. err = txFunc()
  5. return
  6. }

在上面的代码中,表达式*perr计算为WithTransactionerr的当前值。问题中err的值是延迟时err的值。

展开查看全部

相关问题