debuggoCritical
Multiple values in single-value context
Viewed 0 times
contextsinglemultiplevaluevalues
Problem
Due to error handling in Go, I often end up with multiple values functions. So far, the way I have managed this has been very messy and I am looking for best practices to write cleaner code.
Let's say I have the following function:
How can I assign a new variable to
Now I do this:
Isn't there a way to access directly the first returned variable?
Let's say I have the following function:
type Item struct {
Value int
Name string
}
func Get(value int) (Item, error) {
// some code
return item, nil
}How can I assign a new variable to
item.Value elegantly. Before introducing the error handling, my function just returned item and I could simply do this:val := Get(1).ValueNow I do this:
item, _ := Get(1)
val := item.ValueIsn't there a way to access directly the first returned variable?
Solution
In case of a multi-value return function you can't refer to fields or methods of a specific value of the result when calling the function.
And if one of them is an
However there might be situations where you know the code will not fail in any circumstances. In these cases you can provide a helper function (or method) which will discard the
This can be the case if you provide the input values for a function from code, and you know they work.
Great examples of this are the
Examples:
Back to your case
IF you can be certain
But you should not use this in all cases, just when you're sure it succeeds. Usage:
Go 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic
This is available in
Alternative / Simplification
You can even simplify it further if you incorporate the
Usage:
See some interesting / related questions:
How to pass multiple return values to a variadic function?
Return map like 'ok' in Golang on normal functions
And if one of them is an
error, it's there for a reason (which is the function might fail) and you should not bypass it because if you do, your subsequent code might also fail miserably (e.g. resulting in runtime panic).However there might be situations where you know the code will not fail in any circumstances. In these cases you can provide a helper function (or method) which will discard the
error (or raise a runtime panic if it still occurs).This can be the case if you provide the input values for a function from code, and you know they work.
Great examples of this are the
template and regexp packages: if you provide a valid template or regexp at compile time, you can be sure they can always be parsed without errors at runtime. For this reason the template package provides the Must(t Template, err error) Template function and the regexp package provides the MustCompile(str string) *Regexp function: they don't return errors because their intended use is where the input is guaranteed to be valid.Examples:
// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))
// `^[a-z]+\[[0-9]+\]In case of a multi-value return function you can't refer to fields or methods of a specific value of the result when calling the function.
And if one of them is an error, it's there for a reason (which is the function might fail) and you should not bypass it because if you do, your subsequent code might also fail miserably (e.g. resulting in runtime panic).
However there might be situations where you know the code will not fail in any circumstances. In these cases you can provide a helper function (or method) which will discard the error (or raise a runtime panic if it still occurs).
This can be the case if you provide the input values for a function from code, and you know they work.
Great examples of this are the template and regexp packages: if you provide a valid template or regexp at compile time, you can be sure they can always be parsed without errors at runtime. For this reason the template package provides the Must(t Template, err error) Template function and the regexp package provides the MustCompile(str string) *Regexp function: they don't return errors because their intended use is where the input is guaranteed to be valid.
Examples:
is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]In case of a multi-value return function you can't refer to fields or methods of a specific value of the result when calling the function.
And if one of them is an error, it's there for a reason (which is the function might fail) and you should not bypass it because if you do, your subsequent code might also fail miserably (e.g. resulting in runtime panic).
However there might be situations where you know the code will not fail in any circumstances. In these cases you can provide a helper function (or method) which will discard the error (or raise a runtime panic if it still occurs).
This can be the case if you provide the input values for a function from code, and you know they work.
Great examples of this are the template and regexp packages: if you provide a valid template or regexp at compile time, you can be sure they can always be parsed without errors at runtime. For this reason the template package provides the Must(t Template, err error) Template function and the regexp package provides the MustCompile(str string) *Regexp function: they don't return errors because their intended use is where the input is guaranteed to be valid.
Examples:
)Back to your case
IF you can be certain
Get() will not produce error for certain input values, you can create a helper Must() function which would not return the error but raise a runtime panic if it still occurs:func Must(i Item, err error) Item {
if err != nil {
panic(err)
}
return i
}But you should not use this in all cases, just when you're sure it succeeds. Usage:
val := Must(Get(1)).ValueGo 1.18 generics update: Go 1.18 adds generics support, it is now possible to write a generic
Must() function:func Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}This is available in
github.com/icza/gog, as gog.Must() (disclosure: I'm the author).Alternative / Simplification
You can even simplify it further if you incorporate the
Get() call into your helper function, let's call it MustGet:func MustGet(value int) Item {
i, err := Get(value)
if err != nil {
panic(err)
}
return i
}Usage:
val := MustGet(1).ValueSee some interesting / related questions:
How to pass multiple return values to a variadic function?
Return map like 'ok' in Golang on normal functions
Code Snippets
// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))
// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)func Must(i Item, err error) Item {
if err != nil {
panic(err)
}
return i
}val := Must(Get(1)).Valuefunc Must[T any](v T, err error) T {
if err != nil {
panic(err)
}
return v
}func MustGet(value int) Item {
i, err := Get(value)
if err != nil {
panic(err)
}
return i
}Context
Stack Overflow Q#28227095, score: 102
Revisions (0)
No revisions yet.