> In Go, the only way to consume a multi-return is to use a full assignment statement to assign each return value to a variable, and then use the variables.There actually is another way, but it isn't really that handy (as it is basically just shorthand for multiple assignment):
func mustInt(v int, err error) int {
fmt.Printf("got: (%v, %v)\n", v, err)
return v
}
func foobar() (int, error) {
return -123, nil
}
func badbeef() (int, error) {
return nil, fmt.Errorf("moo")
}
func main() {
vals := []any{
mustFn(foobar()),
mustFn(badbeef()),
}
fmt.Printf("got vals: %v\n", vals)
}
You can use generics but it's still not that useful because you are quite limited in what you can do with the return value:
func mustFn[T any](v T, err error) T {
fmt.Printf("got: (%v, %v)\n", v, err)
return v
}
func foobar() (int64, error) {
return -123, nil
}
func deadbeef() (string, error) {
return "weird name for a cafe", nil
}
func badbeef() (*int, error) {
return nil, fmt.Errorf("moo")
}
func main() {
vals := []any{
mustFn(foobar()),
mustFn(deadbeef()),
mustFn(badbeef()),
}
fmt.Printf("got vals: %v\n", vals)
}
You could define your own Result[T any] and do sum types (and people do) but the ergnomics for it are completely awful and readability goes out the window. (Insert grumbling about bolt-on features.)