init() without init() in Go

Jean-François Bustarret
Random Go tips
Published in
2 min readOct 12, 2015

I like when files are as self-contained as possible, and having to put some init logic elsewhere (e.g. in a package-level init() function) irritates me.

Go does not allow code outside functions, the beginner’s reflex is to put all initialization code in a single init(), often in a separate file :

foo.go
func initFoo() {
doSomething("foo")
}
bar.go
func initBar() {
doSomething("bar")
}
baz.go
func doSomething(baz string) {
}
init.go
func init() {
initFoo()
initBar()
}

The goal of this article is to describe alternative initialization patterns.

Multiple init()

Finally, each source file can define its own niladic init function to set up whatever state is required. (Actually each file can have multiple init functions.)
- Effective Go

The following works perfectly :

foo.go
func init() {
doSomething("foo")
}
bar.go
func init() {
doSomething("bar")
}
baz.go
func doSomething(baz string) {
}

While Go supports many init() functions, their ordering is unspecified. So code that happens in init() should not depend on anything else being initialized in another init() somewhere else.

Blank identifier

Go does not allow code outside functions, but it allows to define vars based on function results. The function will be executed during initialization, just before init() is (are) called.

Our init function can return a dummy value we assign to a variable. As we aren’t interested in storing the value, we will use the blank identifier.

The example can be rewritten as :

foo.go
var (
_ = doSomething("foo")
)
bar.go
var (
_ = doSomething("bar")
)
baz.go
func doSomething(baz string) struct{} {
// Do something
return struct{}{}
}

Why use struct{} ? Because struct{}{} is the smallest value usable in Go (it uses 0 bytes of RAM). Because also it is a way of telling : this value has no real meaning, it is just here because Go expects a value here.

Anonymous functions

When the initialization logic is more complex, an anonymous init function can be used :

var (
_ = func() struct{} {
// Do something
return struct{}{}
}()
)

It can also be used to setup a variable :

var (
myVar = func() MyStruct {
m := MyStruct{}
// Do something
return m
}()
)

I will let you choose the scenario that best suits you/your code (but please avoid using a single init() function, you don’t have to !)…

--

--