golang 在一个包中允许多个 init 的目的是什么?

What's the purpose of golang allowing multiple init in one package?

我知道golang允许一个包甚至一个文件中有多个init。 我想知道为什么? 例如,如果一个 pkg 有很多文件,我们可以写多个 init,然后我们可能会迷失应该把 init 放在哪里,如果我们在一个 pkg 中有多个 init,我们也可能对 init 的顺序感到困惑。 (我的意思是这样更好吗?我们只能有 1 个 init,然后我们可以有一些 initXXX,然后将它们放入 init,看起来很干净。) 在代码结构视图中这样做有什么好处?

这个问题可能有点主观,但使用多个包 init() 函数可以使您的代码更易于阅读和维护。

如果您的源文件很大,通常您会按照某种逻辑顺序排列它们的内容(例如类型、变量声明、方法等)。允许多个 init() 函数使您可以将初始化代码放在它们应该初始化的部分附近。如果不允许这样做,您将被迫在每个包中使用一个 init() 函数,并将所有内容放入其中,远离它们需要初始化的变量。

是的,拥有多个 init() 函数可能需要注意执行顺序,但要知道使用多个 init() 函数不是必需的,这只是一种可能性。您可以编写 init() 函数来避免“副作用”,不依赖于其他 init() 函数的完成。

如果这是不可避免的,您可以创建一个“主”init(),它明确控制其他“子”init() 函数的顺序。

一个“主人”init()控制其他初始化函数的例子:

func init() {
    initA()
    initB()
}

func initA() {}
func initB() {}

在上面的示例中,initA() 将始终在 initB() 之前 运行。

规范中的相关部分:Package initialization

另见相关问题:

多个 init() 函数的另一个用例是添加基于构建标签的功能。 init() 函数可用于将挂钩添加到现有包中并扩展其功能。

以下是一个精简示例,演示如何根据构建标签向 CLI 实用程序添加更多命令。

package main

import "github.com/spf13/cobra"

var rootCmd = &cobra.Command{Use: "foo", Short: "foo"}

func init() {
    rootCmd.AddCommand(
        &cobra.Command{Use: "CMD1", Short: "Command1"},
        &cobra.Command{Use: "CMD2", Short: "Command2"},
    )
}

func main() {
    rootCmd.Execute()
}

以上是该实用程序的“原始”版本。

// +build debugcommands

package main

import "github.com/spf13/cobra"

func init() {
    rootCmd.AddCommand(&cobra.Command{Use: "DEBUG-CMD1", Short: "Debug command1"})
}

第二个文件的内容使用在开发过程中最相关的附加命令扩展了标准命令。

使用 go build -tags debugcommands 编译将生成带有添加命令的二进制文件,而省略 -tags 标志将生成标准版本。