Когда приложение Go запускается, все non-test-пакеты инициализируются строго по определённому порядку: сначала инициализируются все импортируемые зависимости (по цепочке), затем непосредственно сам пакет. Для инициализации используются:
Функции init вызываются после инициализации переменных пакета. Если пакет импортируется — его init выполняется один раз до использования переменных/функций этого пакета.
Пример:
var a = getA() func getA() int { fmt.Println("getA called") return 42 } func init() { fmt.Println("init called") } // Выведет: // getA called // init called
Особенности:
Можно ли явно вызвать init-функцию любого пакета?
Ответ: Нет, функция init никогда не вызывается напрямую из кода программы. Она вызывается только рантаймом во время процесса инициализации пакета в заранее определённый момент, вызов init() явно не допускается — приведёт к ошибке компиляции.
История
В проекте два пакета импортировали друг друга для инициализации глобальных переменных через init(). Это привело к циклическим зависимостям и ошибкам при сборке — Go не смог определить корректный порядок инициализации.
История
Причиной сложного бага стало то, что init-функции использовали глобальные переменные пакета, которые ещё не были проинициализированы. Результат: неоднозначное поведение при запуске с непредсказуемыми состояниями.
История
В проекте для side effects импортировали пакет без явного использования (через import _ "some/lib"). После реорганизации кода init-функция нужного пакета вызывалась слишком рано (до инициализации зависимых переменных в другом пакете), возник hard-to-debug баг.