Я знаю, что golang позволяет несколько init в одном пакете и даже в одном файле. Мне интересно, почему? Например, если в pkg есть много файлов, мы могли бы написать несколько init, тогда мы могли бы потеряться в том, где мы должны поместить init, и мы также можем быть смущены порядком init, если у нас есть несколько init в одном pkg. (Я имею в виду, что это лучше? У нас может быть только 1 init, тогда у нас может быть некоторый initXXX, а затем положить их в init, он выглядит довольно чистым). Какое преимущество этого сделать в представлении структуры кода?
Какова цель golang, позволяющая несколько init в одном пакете?
Ответ 1
Этот вопрос может быть основан на мнениях, но использование нескольких функций пакета init()
может облегчить чтение и поддержку вашего кода.
Если ваши исходные файлы имеют большой размер, обычно вы размещаете их содержимое (например, типы, объявления переменных, методы и т.д.) В некотором логическом порядке. Разрешение нескольких функций init()
дает вам возможность поместить код инициализации рядом с частями, которые они должны инициализировать. Если это не будет разрешено, вы будете вынуждены использовать одну функцию init()
для каждого пакета и помещать все в нее, вдали от переменных, которые им нужно инициализировать.
Да, наличие нескольких функций init()
может потребовать некоторой заботы о порядке выполнения, но знайте, что использование нескольких функций init()
- это не требование, а просто возможность. И вы можете написать функции init()
, чтобы не иметь "побочных" эффектов, чтобы не полагаться на завершение других функций init()
.
Если это неизбежно, вы можете создать одного "master" init()
, который явно контролирует порядок других, "child" init()
функций.
Пример "мастера" init()
, управляющего другими функциями инициализации:
func init() {
initA()
initB()
}
func initA() {}
func initB() {}
В приведенном выше примере initA()
всегда будет работать до initB()
.
Соответствующий раздел из спецификации: Инициализация пакета.
См. также связанный вопрос: Что означает лексический порядок имен файлов?
Ответ 2
Еще один вариант использования нескольких функций init()
- добавление функций на основе тегов сборки. Функцию init()
можно использовать для добавления хуков в существующий пакет и расширения его функциональности.
Ниже приведен сжатый пример, демонстрирующий добавление дополнительных команд в утилиту CLI на основе тегов сборки.
package main
import "github.com/spf13/cobra"
var (
rootCmd = &cobra.Command{Use: "foo", Short: "foo"}
)
func main() {
rootCmd.AddCommand(
&cobra.Command{Use: "CMD1", Short: "Command1"},
&cobra.Command{Use: "CMD1", Short: "Command1"},
)
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
создаст стандартную версию.