Quando o init() é acionado em Go? Análise com exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Quando o init() é executado em Go? Analisamos com um exemplo real



Imagine: você está escrevendo um microsserviço em Go. Em um dos pacotes, você declarou init() para carregar a configuração. Você inicia a aplicação — e de repente ela falha com nil pointer dereference. Você entra em pânico: "Por quê? A configuração deveria ter sido carregada primeiro!"



Familiar? Se sim, você não está sozinho. A pergunta "When does the init() function run?" é uma das mais populares no Stack Overflow (milhares de visualizações). Vamos entender de uma vez por todas quando e em que ordem o init() é acionado em Go, para que você não caia mais nessa armadilha.



O que é init() e para que serve?



Em Go, init() é uma função especial sem parâmetros e sem valor de retorno. Ela não é chamada explicitamente. O runtime do Go a executa automaticamente antes da execução da função main().



Para que serve?



  • Inicialização de variáveis globais que exigem lógica complexa (por exemplo, leitura de arquivo).
  • Registro de drivers de banco de dados ou manipuladores HTTP.
  • Verificação do ambiente (variáveis de ambiente, disponibilidade de recursos).


Mas a regra principal é: você nunca deve confiar na ordem de execução do init() entre diferentes arquivos do mesmo pacote. E eis porquê.



Quando exatamente o init() é acionado? A ordem exata



O Go executa o init() seguindo regras rigorosas. Vamos detalhá-las.



Regra nº1: Um pacote — uma ordem

Dentro de um mesmo pacote, o init() é executado na ordem de declaração dos arquivos (em ordem alfabética dos nomes dos arquivos). Mas isso é um detalhe de implementação — é melhor não depender disso.



Regra nº2: Primeiro a inicialização de variáveis, depois o init()

Antes de chamar o init(), o Go inicializa todas as variáveis globais no pacote. Se uma variável depende de outra variável do mesmo pacote — a ordem de declaração delas é importante.



package config

var AppName string = "MyApp"var Version string = getVersion() // será chamado antes do init()

func init() { // Aqui AppName e Version já estão disponíveis println("Init iniciado para", AppName)}

func getVersion() string { return "1.0.0"}


Regra nº3: Pacotes importados são inicializados primeiro

Esta é a regra mais importante. Se o pacote A importa o pacote B, então primeiro todos os init() no pacote B são executados, e só depois os do A. O Go constrói um grafo de dependências e executa a inicialização "de baixo para cima".



// Pacote databasepackage database

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

// Pacote main (importa database)package main

import "myapp/database"

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

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

// Saída:// 1. database init// 2. main init// 3. main function


Regra nº4: Vários init() no mesmo arquivo — pode, mas não precisa

Em um mesmo arquivo pode haver vários init(). Eles serão executados na ordem de declaração. Mas isso dificulta a leitura do código. É melhor unificar a lógica em uma única função.



Exemplo prático: o que acontece se errar a ordem?



Vamos simular um erro típico de iniciante. Suponha que temos um pacote config, que lê as configurações de um arquivo, e um pacote app, que usa essas configurações.



// config.gopackage config

var Settings map[string]string

func init() { // Simulando a leitura de arquivo Settings = map[string]string{ "port": "8080", "host": "localhost", } println("Config carregado")}

// app.gopackage app

import "myapp/config"

var ServerPort string

func init() { // ERRO: se config.Settings ainda não foi inici

Blogs

Book Recommendations