go / must
I use must helpers to simplify initialization code
where errors indicate programmer mistakes, not runtime conditions.
The pattern
package must
// Do panics if err is non-nil.
func Do(err error) {
if err != nil {
panic(err)
}
}
// Get returns v as-is. It panics if err is non-nil.
func Get[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}
Usage
Package-level initialization where errors are bugs:
var (
homeDir = must.Get(os.UserHomeDir())
configRe = must.Get(regexp.Compile(`^[a-z]+$`))
baseURL = must.Get(url.Parse("https://api.example.com"))
)
Cleanup where errors are unexpected:
defer must.Do(f.Close())
defer must.Do(rows.Close())
When to use
Use must when:
- The error indicates a programming mistake (invalid regex, malformed URL literal)
- Failure during initialization means the program can't run anyway
- You're in a test and want to fail fast
Don't use must when:
- The error depends on runtime input (user data, network, filesystem)
- Recovery is possible
- You're in library code that others will call
Comparison
Without must:
re, err := regexp.Compile(`^[a-z]+$`)
if err != nil {
panic(err) // or log.Fatal
}
With must:
re := must.Get(regexp.Compile(`^[a-z]+$`))
The intent is clearer: this must succeed or the program is broken.