reference
Effective Go – The Go Programming Language (google.cn)
Initialize | the Effective and efficient Go programming Go 2020 | Go technology BBS (learnku.com)
While on the surface, Go’s initialization process is not that different from C or C++, it is more powerful. During initialization, not only can complex structures be built, but the initialization sequence between different package objects can be handled correctly.
Constants constant
Constants in Go are invariants. They are created at compile time, even though they may be local variables defined in a function. Constants can only be numbers, characters (runes), strings, or Bores. Because of compile-time constraints, the expression that defines them must also be a constant expression that can be evaluated by the compiler. For example, 1<<3 is a constant expression, but math.sin (math.pi /4) is not, because function calls to math.sin only occur at run time.
In Go, enumeration constants are created using the enumerator IOTA. Because IOTA can be part of an expression that can be repeated implicitly, it is easier to build complex collections of values.
type ByteSize float64
const (
_ = iota // ignore first value by assigning to blank identifier
KB ByteSize = 1 << (10 * iota)
MB
GB
TB
PB
EB
ZB
YB
)
Copy the code
User-defined types can override the String method, so it opens up the possibility of automatically formatting arbitrary values when printing, even as part of a generic type. Although you’ll often see this technique applied to structures, it’s also useful for types like floating-point scalars such as ByteSize.
func (b ByteSize) String() string {
switch {
case b >= YB:
return fmt.Sprintf("%.2fYB", b/YB)
case b >= ZB:
return fmt.Sprintf("%.2fZB", b/ZB)
case b >= EB:
return fmt.Sprintf("%.2fEB", b/EB)
case b >= PB:
return fmt.Sprintf("%.2fPB", b/PB)
case b >= TB:
return fmt.Sprintf("%.2fTB", b/TB)
case b >= GB:
return fmt.Sprintf("%.2fGB", b/GB)
case b >= MB:
return fmt.Sprintf("%.2fMB", b/MB)
case b >= KB:
return fmt.Sprintf("%.2fKB", b/KB)
}
return fmt.Sprintf("%.2fB", b)
}
Copy the code
The expression YB prints 1.00yb, while ByteSize(1e13) prints 9.09.
It’s safe to use Sprintf to implement ByteSize’s String method here (it’s not infinitely recursive), not because of the conversion, but because it calls Sprintf in %f, which is not a String format: Sprintf only calls String if it needs a String, and %f requires a floating-point value.
FMT. Println (YB, ByteSize e13) (1)/YB / 1.00 9.09 TBCopy the code
The Variables Variables
Variables can be initialized like constants, and can be initialized to a plain expression that yields a result at run time.
The init function
Finally, each source file can set some necessary state by defining its own parameterless init function. (Each file can have multiple init functions.) When it ends, initialization ends: Init is called only after all variable declarations in the package have been evaluated by their initializer, and variables in the package are evaluated only after all imported packages have been initialized.
Except for initializations that cannot be represented as declarations. The init() function is automatically executed after each package is initialized and takes precedence over the main function. The init function is usually used to:
- Initialize a variable
- Check/fix the status of the program
- registered
- Run a calculation
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")
}
Copy the code