Just a couple small notes before we move on from return statements…
Return statements
…
Regardless of how they are declared, all the result values are initialized to the zero values for their type upon entry to the function. A “return” statement that specifies results sets the result parameters before any deferred functions are executed.
For the most part, this can be considered trivia, for Quiz night at your next Go meetup. The only time it makes a practical difference in day-to-day programming is when using named return values, as this is how you can modify a return value in a defer
statement.
func foo() (err error) {
f, err := f.Open("somefile.txt")
if err != nil {
return err
}
defer func() {
if e := f.Close(); e != nil && err == nil {
err = e
}
}()
/* do something with f */
}
Implementation restriction: A compiler may disallow an empty expression list in a “return” statement if a different entity (constant, type, or variable) with the same name as a result parameter is in scope at the place of the return.
func f(n int) (res int, err error) { if _, err := f(n-1); err != nil { return // invalid return statement: err is shadowed } return }
In short, I consider this just one more reason to avoid naked returns.
Quotes from The Go Programming Language Specification Language version go1.22 (Feb 6, 2024)