4/06/2025

Go语言中的init函数

 

1. init函数的作用

  • 包初始化init函数用于在包被导入时执行初始化任务(如配置资源、注册组件等)。

  • 可重复定义:同一个包中可以定义多个init函数,它们会按顺序执行。


2. init函数的执行顺序

(1)同一个Go文件中的多个init函数

  • 按代码中的定义顺序执行。

go
复制
// a.go 文件内
func init() { fmt.Println("init 1") }
func init() { fmt.Println("init 2") }
// 输出:init 1 → init 2

(2)同一个包中的不同文件

  • 文件名排序(字典序)执行各文件中的init

  • 例如:a.goinit先于b.goinit执行。

(3)不同包的init函数

  • 依赖关系从最深到最浅执行:

    1. 被导入的包init优先于当前包init

    2. 若包A导入包B,包B导入包C,则执行顺序为:C → B → A。

  • 同一层级按import语句的顺序执行。


3. Go程序的完整初始化顺序

  1. 被导入的包

    • 递归初始化其依赖的包。

    • 初始化包级变量和常量。

    • 执行包的init函数。

  2. 当前包

    • 初始化包级变量和常量。

    • 执行当前包的init函数。

  3. main函数

    • 最后执行main包的main函数。

正确顺序总结

text
复制
被导入包的变量/常量 → 被导入包的init → 当前包的变量/常量 → 当前包的init → main函数

4. 其他关键规则

(1)init函数的唯一性

  • 即使一个包被多次导入(如多个包依赖它),其init函数仅执行一次(包级单例)。

(2)执行环境

  • 所有init函数在同一个goroutine中按顺序执行,不存在并发问题。

(3)避免循环导入

  • Go禁止循环导入(如包A导入包B,包B又导入包A),需通过设计解耦。


示例代码验证

场景

  • deep(依赖层次最深) → 包middle → 包main

go
复制
// deep/init.go
package deep
func init() { fmt.Println("deep init") }

// middle/init.go
package middle
import _ "deep"
func init() { fmt.Println("middle init") }

// main.go
package main
import _ "middle"
func init() { fmt.Println("main init") }
func main() { fmt.Println("main") }

输出

text
复制
deep init → middle init → main init → main

常见误区纠正

  • 错误理解:当前包的init先于其变量/常量初始化。

    • 正确顺序:当前包的变量/常量初始化 → 当前包的init执行。

  • 错误理解:不同包的initimport顺序直接执行。

    • 正确逻辑:依赖的最深包最先初始化(递归处理)。


通过理解init的执行顺序和规则,可以避免初始化时的依赖问题,确保资源按预期正确初始化。

Ubuntu linux修改dns服务器

在Ubuntu Linux系统中,修改DNS服务器分为临时和永久两种方式,具体方法如下: ---  一、临时修改DNS(重启后失效)  方法1:直接修改 `/etc/resolv.conf` bash sudo nano /etc/resolv.conf 删除原有 `namese...