Documentation
¶
Overview ¶
Package try emulates aspects of the ill-fated "try" proposal using generics. See https://golang.org/issue/32437 for inspiration.
Example usage:
func Fizz(...) (..., err error) { defer try.HandleF(&err, func() { if err == io.EOF { err = io.ErrUnexpectedEOF } }) ... := try.E2(Buzz(...)) return ..., nil }
This package is a sharp tool and should be used with care. Quick and easy error handling can occlude critical error handling logic. Panic handling generally should not cross package boundaries or be an explicit part of an API.
Package try is a good fit for short Go programs and unit tests where development speed is a greater priority than reliability. Since the E functions panic if an error is encountered, recovering in such programs is optional.
Code before try:
func (a *MixedArray) UnmarshalNext(uo json.UnmarshalOptions, d *json.Decoder) error { switch t, err := d.ReadToken(); { case err != nil: return err case t.Kind() != '[': return fmt.Errorf("got %v, expecting array start", t.Kind()) } if err := uo.UnmarshalNext(d, &a.Scalar); err != nil { return err } if err := uo.UnmarshalNext(d, &a.Slice); err != nil { return err } if err := uo.UnmarshalNext(d, &a.Map); err != nil { return err } switch t, err := d.ReadToken(); { case err != nil: return err case t.Kind() != ']': return fmt.Errorf("got %v, expecting array end", t.Kind()) } return nil }
Code after try:
func (a *MixedArray) UnmarshalNext(uo json.UnmarshalOptions, d *json.Decoder) (err error) { defer try.Handle(&err) if t := try.E1(d.ReadToken()); t.Kind() != '[' { return fmt.Errorf("found %v, expecting array start", t.Kind()) } try.E(uo.UnmarshalNext(d, &a.Scalar)) try.E(uo.UnmarshalNext(d, &a.Slice)) try.E(uo.UnmarshalNext(d, &a.Map)) if t := try.E1(d.ReadToken()); t.Kind() != ']' { return fmt.Errorf("found %v, expecting array end", t.Kind()) } return nil }
Quick tour of the API ¶
The E family of functions all remove a final error return, panicking if non-nil.
Handle recovers from that panic and allows assignment of the error to a return error value. Other panics are not recovered.
func f() (err error) { defer try.Handle(&err) ... }
HandleF is like Handle, but it calls a function after any such assignment.
func f() (err error) { defer try.HandleF(&err, func() { if err == io.EOF { err = io.ErrUnexpectedEOF } }) ... } func foo(i int) (err error) { defer try.HandleF(&err, func() { err = fmt.Errorf("unable to foo %d: %w", i, err) }) ... }
F wraps an error with file and line information and calls a function on error. It inter-operates well with testing.TB and log.Fatal.
func TestFoo(t *testing.T) { defer try.F(t.Fatal) ... } func main() { defer try.F(log.Fatal) ... }
Recover is like F, but it supports more complicated error handling by passing the error and runtime frame directly to a function.
func f() { defer try.Recover(func(err error, frame runtime.Frame) { // do something useful with err and frame }) ... }
Index ¶
- func E(err error)
- func E1[A any](a A, err error) A
- func E2[A, B any](a A, b B, err error) (A, B)
- func E3[A, B, C any](a A, b B, c C, err error) (A, B, C)
- func E4[A, B, C, D any](a A, b B, c C, d D, err error) (A, B, C, D)
- func F(fn func(...any))
- func Handle(errptr *error)
- func HandleF(errptr *error, fn func())
- func Recover(fn func(err error, frame runtime.Frame))
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func F ¶
func F(fn func(...any))
F recovers an error previously panicked with an E function, wraps it, and passes it to fn. The wrapping includes the file and line of the runtime frame in which it occurred. F pairs well with testing.TB.Fatal and log.Fatal.
func Handle ¶
func Handle(errptr *error)
Handle recovers an error previously panicked with an E function and stores it into errptr.
Types ¶
This section is empty.