Now we’re going to look at the third and finaly way to return values from a function in Go.
But first a warning.
⚠️ NEVER DO THIS!! ⚠️
What we’re about to look at is commonly referred to as “naked returns” or “bare returns”, and it is widely (though, admittedly, not universally) considered bad practice. It’s honestly a mystery to me why this feature exists in Go, and I wish it didn’t. It hurts readability, sometimes very severely. For more on why not to do this, and alternatives, checkout my video on the subject.
Return statements
…
- The expression list may be empty if the function’s result type specifies names for its result parameters. The result parameters act as ordinary local variables and the function may assign values to them as necessary. The “return” statement returns the values of these variables.
func complexF3() (re float64, im float64) { re = 7.0 im = 4.0 return } func (devnull) Write(p []byte) (n int, _ error) { n = len(p) return }
So in short, when you name your return values in the function’s result list, this implicitly creates the variables for you, with their respective zero values. So far, this might be seen as a minor convenience:
func foo() (name string) {
is a bit shorter than the (mostly) equivalent:
func foo() string {
var name string
But, this also gives you the option (though let me stress: it’s not a requirement) to then omit the names of the return values in your return
statement.
func foo() (name string) {
name = "Bob"
return
}
This is valid Go. This is ugly Go. Don’t do this.
For a short function like this, it’s not a big deal. But when you have a longer function, and you come across some code that looks like this:
if thingyMajigIsValid() {
return
}
you don’t know what you’re returning. You could be returning from a function with no return values. Or you might be naked-returning 18 different values implicitly. The only way to be sure is to scroll up to the top of the function, to see how it’s defined.
And even that can be deceptive, if you’re inside of a closure:
func foo() { // No return values!
x, y, z := func() (I, fooled, you string) {
I = "this is an interesting string"
fooled = "this one isn't so interesting"
you = "mildly interesting. Maybe."
if thingyMajigIsValid() {
return
}
return "", "", ""
}()
fmt.Println(x, y, z)
}
Fortunately, even when using named return values (which have uses beyond naked returns), you can still name all your return values:
if thingyMajigIsValid() {
return I, fooled, you
}
So if you want my advice, never use naked returns, even when it’s an option for you. Always name your return values, to make reading your code easier.
Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)