-3
func someFunc() (err error) {
    defer func(err_ error) {
        r.handleErrOrPanic(err_, obj) 
    }(err) // err is always nil here
    err = ThrowErrOrPanic(ctx, obj)
    return err
}

I would like to use handleErrOrPanic as a deferred function to handle the error or the panic. I have to define it before ThrowErrOrPanic, since the deferred function has to handle the panic. However, if I define it before err is always nil. How do I solve this?

User12547645
  • 6,955
  • 3
  • 38
  • 69
  • 1
    In the deferred func use the *named return value* of the surrounding function, i.e. use `err` not `err_`. – mkopriva Sep 26 '22 at 14:35
  • That was the setup I tried, but I always get `nil` as `err`. `err` seems to get copied into the deferred function. Changing the value later on does not seem to help. – User12547645 Sep 26 '22 at 14:43
  • 1
    If `nil` is returned by the surrounding function then `err` will be `nil` of course, if you got panic and you want to recover from it use `recover()` in the deferred func. panic & error are not one and the same. – mkopriva Sep 26 '22 at 14:55
  • 1
    Provide a [mcve] if you think your original setup was as suggested but didn't work as advertised. – mkopriva Sep 26 '22 at 14:56
  • And just in case it wasn't clear, in the first comment when I suggested you use `err` instead of `err_`, I meant use *that* `err` that's declared by the surrounding func. Do not pass it as argument to the deferred func. Have the deferred closure reference the variable declared in the outer scope instead. – mkopriva Sep 26 '22 at 14:58
  • 2
    The above advice is sound. FYI, if you're curious why `err` is always nil - it's because defer function parameters are evaluated at the point in time of the defer statements appearance - and *NOT* at the point in time of the defer functions eventual execution. So since `err` - as a named return variable - its default value is nil, and thus the defer function will always be called with a `nil` value. – colm.anseo Sep 26 '22 at 15:08

1 Answers1

2

In the deferred func use the named return value of the surrounding function, i.e. use err not err_. If you got panic and you want to recover from it use recover() in the deferred func.

func someFunc() (err error) {
    defer func() {
        if x := recover(); x != nil { // panic occurred?
            // handle panic
        } else if err != nil { // a plain error occurred?
            // handle error
        } else {
            // all good
        }
    }()

    err = ThrowErrOrPanic(ctx, obj)
    return err
}

https://go.dev/play/p/miTr-lN1Y9R

mkopriva
  • 35,176
  • 4
  • 57
  • 71