¿Cuándo se activa init() en Go? Análisis con ejemplos

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

¿Cuándo se ejecuta init() en Go? Lo analizamos con un ejemplo real



Imagina: estás escribiendo un microservicio en Go. En uno de los paquetes declaraste init() para cargar la configuración. Ejecutas la aplicación — y de repente falla con nil pointer dereference. Entras en pánico: "¿Por qué? ¡Se suponía que la configuración se cargara primero!"



¿Te suena familiar? Si es así, no estás solo. La pregunta "¿Cuándo se ejecuta la función init()?" es una de las más populares en Stack Overflow (miles de visitas). Aclaremos de una vez por todas cuándo y en qué orden se ejecuta init() en Go, para que no caigas más en esta trampa.



¿Qué es init() y para qué sirve?



En Go, init() es una función especial sin parámetros ni valor de retorno. No se llama explícitamente. El runtime de Go la ejecuta automáticamente antes de ejecutar la función main().



¿Para qué sirve?



  • Inicializar variables globales que requieren lógica compleja (por ejemplo, lectura de un archivo).
  • Registrar controladores de bases de datos o manejadores HTTP.
  • Verificar el entorno (variables de entorno, disponibilidad de recursos).


Pero la regla principal es: nunca debes confiar en el orden de ejecución de init() entre diferentes archivos de un mismo paquete. Y he aquí por qué.



¿Cuándo se ejecuta exactamente init()? El orden preciso



Go ejecuta init() siguiendo reglas estrictas. Vamos a desglosarlas paso a paso.



Regla n.º 1: Un paquete, un orden

Dentro de un mismo paquete, init() se ejecuta en el orden de declaración de los archivos (por orden alfabético de los nombres de archivo). Pero esto es un detalle de implementación — es mejor no basarse en ello.



Regla n.º 2: Primero la inicialización de variables, luego init()

Antes de llamar a init(), Go inicializa todas las variables globales del paquete. Si una variable depende de otra variable del mismo paquete, el orden de declaración es importante.



package config

var AppName string = "MyApp"var Version string = getVersion() // se llamará antes de init()

func init() { // Aquí ya están disponibles AppName y Version println("Init iniciado para", AppName)}

func getVersion() string { return "1.0.0"}


Regla n.º 3: Los paquetes importados se inicializan primero

Esta es la regla más importante. Si el paquete A importa el paquete B, primero se ejecutarán todos los init() del paquete B, y solo después los de A. Go construye un grafo de dependencias y ejecuta la inicialización "de abajo hacia arriba".



// Paquete databasepackage database

func init() { println("1. database init")}

// Paquete main (importa database)package main

import "myapp/database"

func init() { println("2. main init")}

func main() { println("3. main function")}

// Salida:// 1. database init// 2. main init// 3. main function


Regla n.º 4: Varios init() en un mismo archivo — se puede, pero no es necesario

En un mismo archivo puede haber varios init(). Se ejecutarán en el orden de declaración. Pero esto dificulta la lectura del código. Es mejor unificar la lógica en una sola función.



Ejemplo práctico: ¿qué sucede si te equivocas con el orden?



Simulemos un error típico de principiante. Supongamos que tenemos un paquete config que lee la configuración de un archivo, y un paquete app que utiliza esa configuración.



// config.gopackage config

var Settings map[string]string

func init() { // Simulamos la lectura del archivo Settings = map[string]string{ "port": "8080", "host": "localhost", } println("Configuración cargada")}

// app.gopackage app

import "myapp/config"

var ServerPort string

func init() { // ERROR: si config.Settings aún no se ha inicializado

Blogs

Book Recommendations