¿Cuándo se ejecuta la función init()?

Resuelto Charlie Parker asked hace 10 años • 11 respuestas

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 initializerssignifica? ¿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.

Charlie Parker avatar Jul 17 '14 03:07 Charlie Parker
Aceptado

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 initfunció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 que go buildfunciona 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

OneOfOne avatar Jul 16 '2014 20:07 OneOfOne

Mira esta foto. :)

import --> const --> var --> init()

  1. Si un paquete importa otros paquetes, los paquetes importados se inicializan primero.

  2. La constante del paquete actual se inicializó entonces.

  3. Luego se inicializan las variables del paquete actual.

  4. 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.

weaming avatar Apr 14 '2018 11:04 weaming

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.gocontienen funciones, pero cuando se ejecuta , la función se ejecuta primero (lo que provocó router.goque 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.goo config.go, se ejecutará antes de que init()se ejecute CUALQUIERA.

rifflock avatar Dec 09 '2014 21:12 rifflock