¿Cuándo se ejecuta la función init()?
Intenté encontrar una explicación precisa de lo que init()
hace la función en Go. Leí lo que dice Effective Go pero no estaba seguro de haber entendido completamente lo que decía. La frase exacta de la que no estoy seguro es la siguiente:
Y finalmente significa finalmente: init se llama después de que todas las declaraciones de variables en el paquete hayan evaluado sus inicializadores, y estos se evalúan solo después de que se hayan inicializado todos los paquetes importados.
¿Que all the variable declarations in the package have evaluated their initializers
significa? ¿Significa que si declara variables "globales" en un paquete y sus archivos, init() no se ejecutará hasta que se evalúe todo y luego ejecutará todas las funciones init y luego main() cuando se ejecute ./main_file_name?
También leí el libro de Mark Summerfield lo siguiente:
Si un paquete tiene una o más funciones init(), se ejecutan automáticamente antes de llamar a la función main() del paquete principal.
Según tengo entendido, init()
solo es relevante cuando pretendes ejecutar main() ¿verdad? Alguien entiende con mayor precisión init()
no dude en corregirme.
Sí, suponiendo que tengas esto :
var WhatIsThe = AnswerToLife()
func AnswerToLife() int { // 1
return 42
}
func init() { // 2
WhatIsThe = 0
}
func main() { // 3
if WhatIsThe == 0 {
fmt.Println("It's all a lie.")
}
}
AnswerToLife()
Se garantiza que se ejecutará antes de init()
que se llame y init()
se garantiza que se ejecutará antes de main()
que se llame.
Tenga en cuenta que init()
siempre se llama, independientemente de si hay main o no, por lo que si importa un paquete que tiene una init
función, se ejecutará.
Además, puedes tener múltiples init()
funciones por paquete; se ejecutarán en el orden en que aparecen en el archivo (después de que se inicialicen todas las variables, por supuesto). Si abarcan varios archivos, se ejecutarán en el orden léxico del nombre del archivo (como lo señala @benc ):
Parece que
init()
las funciones se ejecutan en el orden léxico del nombre del archivo. La especificación Go dice que "se recomienda que los sistemas de compilación presenten varios archivos que pertenecen al mismo paquete en orden léxico de nombre de archivo a un compilador". Parece quego build
funciona de esta manera.
Muchos de los paquetes internos de Go se utilizan init()
para inicializar tablas y demás, por ejemplo https://github.com/golang/go/blob/883bc6/src/compress/bzip2/bzip2.go#L480
Mira esta foto. :)
import --> const --> var --> init()
Si un paquete importa otros paquetes, los paquetes importados se inicializan primero.
La constante del paquete actual se inicializó entonces.
Luego se inicializan las variables del paquete actual.
Finalmente,
init()
se llama a la función del paquete actual.
Un paquete puede tener múltiples funciones de inicio (ya sea en un solo archivo o distribuidas en varios archivos) y se llaman en el orden en que se presentan al compilador.
Un paquete se inicializará sólo una vez incluso si se importa desde varios paquetes.
Algo que agregar a esto (que habría agregado como comentario, pero al momento de escribir esta publicación aún no tenía suficiente reputación)
Al tener varios inicios en el mismo paquete, todavía no he encontrado ninguna forma garantizada de saber en qué orden se ejecutarán. Por ejemplo tengo:
package config
- config.go
- router.go
Ambos config.go
contienen funciones, pero cuando se ejecuta , la función se ejecuta primero (lo que provocó router.go
que mi aplicación entre en pánico).init()
router.go
Si se encuentra en una situación en la que tiene varios archivos, cada uno con su propia init()
función, tenga en cuenta que no está garantizado que obtenga uno antes que el otro. Es mejor utilizar una asignación de variable como muestra OneToOne en su ejemplo. La mejor parte es: esta declaración de variable ocurrirá antes de TODAS init()
las funciones del paquete.
Por ejemplo
config.go:
var ConfigSuccess = configureApplication()
func init() {
doSomething()
}
func configureApplication() bool {
l4g.Info("Configuring application...")
if valid := loadCommandLineFlags(); !valid {
l4g.Critical("Failed to load Command Line Flags")
return false
}
return true
}
enrutador.go:
func init() {
var (
rwd string
tmp string
ok bool
)
if metapath, ok := Config["fs"]["metapath"].(string); ok {
var err error
Conn, err = services.NewConnection(metapath + "/metadata.db")
if err != nil {
panic(err)
}
}
}
independientemente de si var ConfigSuccess = configureApplication()
existe en router.go
o config.go
, se ejecutará antes de que init()
se ejecute CUALQUIERA.