Generic "must" helper for Go

· 227 words · 2 minute read

Go error handling can be a bit verbose. There are a lot of places where errors are unlikely or where they are so critical that a panic is preferred. Because of this there are lots of Must* -helpers in various packages. E.g. regexp.MustCompile.

Let’s take a closer look at regexp.MustCompile:

// MustCompile is like Compile but panics if the expression cannot be parsed.
// It simplifies safe initialization of global variables holding compiled regular
// expressions.
func MustCompile(str string) *Regexp {
	regexp, err := Compile(str)
	if err != nil {
		panic(`regexp: Compile(` + quote(str) + `): ` + err.Error())
	}
	return regexp
}

These helpers have naturally been written before generics were introduced. They typically couldn’t be reused, because different functions have different return types. But Go has had generics for a while now, so we can use them to implement a … generic Must-function:

func Must[T any](v T, err error) T {
	if err != nil {
		panic(err)
	}

	return v
}

Usage is quite simple:

re := regexp.MustCompile(`\d+`)
re2 := Must(regexp.Compile(`\d+`))

We could also define a currying version:

func CurryMust[T any, U any](f func(T) (U, error)) func(T) U {
	return func(v T) U {
		w, err := f(v)
		if err != nil {
			panic(err)
		}

		return w
	}
}

But using it isn’t necessarily any nicer:

re := CurryMust(regexp.Compile)(`\d+`)
compile := CurryMust(regexp.Compile)
re2 := compile(`\d+`)