Initialization
source ↗Initialization
Although it doesn’t look superficially very different from initialization in C or C++, initialization in Go is more powerful. Complex structures can be built during initialization and the ordering issues among initialized objects, even among different packages, are handled correctly.
Constants
Constants in Go are just that—constant.
They are created at compile time, even when defined as
locals in functions,
and can only be numbers, characters (runes), strings or booleans.
Because of the compile-time restriction, the expressions
that define them must be constant expressions,
evaluatable by the compiler. For instance,
1<<3 is a constant expression, while
math.Sin(math.Pi/4) is not because
the function call to math.Sin needs
to happen at run time.
In Go, enumerated constants are created using the iota
enumerator. Since iota can be part of an expression and
expressions can be implicitly repeated, it is easy to build intricate
sets of values.
The ability to attach a method such as String to any
user-defined type makes it possible for arbitrary values to format themselves
automatically for printing.
Although you’ll see it most often applied to structs, this technique is also useful for
scalar types such as floating-point types like ByteSize.
The expression YB prints as 1.00YB,
while ByteSize(1e13) prints as 9.09TB.
The use here of Sprintf
to implement ByteSize’s String method is safe
(avoids recurring indefinitely) not because of a conversion but
because it calls Sprintf with %f,
which is not a string format: Sprintf will only call
the String method when it wants a string, and %f
wants a floating-point value.
Variables
Variables can be initialized just like constants but the initializer can be a general expression computed at run time.
var (
home = os.Getenv("HOME")
user = os.Getenv("USER")
gopath = os.Getenv("GOPATH")
)
The init function
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.)
And finally means finally: init is called after all the
variable declarations in the package have evaluated their initializers,
and those are evaluated only after all the imported packages have been
initialized.
Besides initializations that cannot be expressed as declarations,
a common use of init functions is to verify or repair
correctness of the program state before real execution begins.
func init() {
if user == "" {
log.Fatal("$USER not set")
}
if home == "" {
home = "/home/" + user
}
if gopath == "" {
gopath = home + "/go"
}
// gopath may be overridden by --gopath flag on command line.
flag.StringVar(&gopath, "gopath", gopath, "override default GOPATH")
}