【Golang】包加载(Package Initialization)

Posted by 西维蜀黍 on 2021-02-25, Last Modified on 2021-10-17

Package Initialization 包括两部分

  • 变量初始化
  • init() functions

变量初始化

  • Within a package, package-level variable initialization proceeds stepwise, with each step selecting the variable earliest in declaration order which has no dependencies on uninitialized variables.
  • More precisely, a package-level variable is considered ready for initialization if it is not yet initialized and either has no initialization expression or its initialization expression has no dependencies on uninitialized variables.
  • The declaration order of variables declared in multiple files is determined by the order in which the files are presented to the compiler: Variables declared in the first file are declared before any of the variables declared in the second file, and so on.

Demo

// sw_pprof.go
package main

import (
	"fmt"
)

var swV1 = privateF()
var swV2 = privateF2()

func privateF() int {
	fmt.Println("call main's privateF")
	return 5
}

func privateF2() int {
	fmt.Println("call main's privateF2")
	return 5
}

func init() {
	fmt.Println("call main's init")
}

func main() {}

输出:

call main's privateF
call main's privateF2
call main's init

Within a package, package-level variable initialization proceeds stepwise, with each step selecting the variable earliest in declaration order which has no dependencies on uninitialized variables.

More precisely, a package-level variable is considered ready for initialization if it is not yet initialized and either has no initialization expression or its initialization expression has no dependencies on uninitialized variables. Initialization proceeds by repeatedly initializing the next package-level variable that is earliest in declaration order and ready for initialization, until there are no variables ready for initialization.

For example, given the declarations

package main

import "fmt"

var (
	a = c + b  // == 9
	b = f()    // == 4
	c = f()    // == 5
	d = 3      // == 5 after initialization has finished
)

func f() int {
	d++
	return d
}

func main() {
	fmt.Printf("a: %v, b: %v, c: %v, d: %v", a, b, c, d)
}

the initialization order is d, b, c, a. Note that the order of subexpressions in initialization expressions is irrelevant: a = c + b and a = b + c result in the same initialization order in this example.

输出:

a: 9, b: 4, c: 5, d: 5

init() functions

Variables may also be initialized using init functions.

func init() { … }

Multiple such functions may be defined. They cannot be called from inside a program.

  • A package with no imports is initialized
    • by assigning initial values to all its package-level variables,
    • followed by calling all init() functions in the order they appear in the file.
    • If multiple files have init() , these init() functions will be called in the order of its lexical file name
  • Imported packages are initialized before the package itself.
  • Each package is initialized once, regardless if it’s imported by multiple other packages.

It follows that there can be no cyclic dependencies.

Misc:

  • Package initialization happens in a single goroutine, sequentially, one package at a time.
  • An init function may launch other goroutines, which can run concurrently with the initialization code. However, initialization always sequences the init functions: it will not invoke the next one until the previous one has returned.

Reference