Immediately Invoked Function Expressions
This is a quite frequent code pattern: An anonymous function that is defined and immediately invoked as a goroutine.
go func() {
//...
}()
This is possible because functions in Go can be expressions. The following two function definitions are equivalent:
func f() int {return 2}
g := func() int {return 4}
The second function definition is an expression at the right-hand side of an assignment. The function can be called like a “normal” function: n := g()
.
I guess you already have an idea where this is going to. Yes, you can combine a function expression and the immediate invocation pattern from the goroutine to form an Immediately Invoked Function Expression (IIFE):
n := func() int {return 8}()
What would that be good for? Here are some use cases and situation where IIFE can be advantageous:
- Complex variable initialization at startup. For example, you might need to initialize a variable with a random value, and this initialization requires more than an call to
math/rand
orcrypto/rand
. - No need for using a frowned-upon
func init()
in your modules. - Avoid polluting a module's function namespace with names of one-time functions. Keep function definitions inside the minimal possible scope of usage.
But don't overuse this pattern. While it may be useful in certain situations, it has a drawback. Compare these two lines:
g := func() int {return 4}
n := func() int {return 8}()
From a quick glance, it is hard to tell the difference. Two innocent-looking parentheses at the very end of the line completely change the result of the assignment. g
is a func
waiting to be called, whereas n
is the result of a function that has been called already.
Put that pattern into the category “clever”, and remember the Go proverb:
Clear is better than clever.