По возможности избегайте init(). Когда init() неизбежен или желателен, код должен попытаться:
- Будьте полностью детерминированными, независимо от программной среды или вызова.
- Избегайте зависимости от порядка или побочных эффектов других функций init(). Хотя порядок init() хорошо известен, код может меняться, и, таким образом, отношения между функциями init() могут сделать код хрупким и подверженным ошибкам.
- Избегайте доступа или манипулирования глобальным состоянием или состоянием среды, таким как машинная информация, переменные среды, рабочий каталог, программные аргументы/входные данные и т. д.
- Избегайте операций ввода-вывода, включая вызовы файловой системы, сети и системные вызовы.
Код, который не может удовлетворить эти требования, скорее всего, принадлежит как помощник, который будет вызываться как часть main() (или где-то еще в жизненном цикле программы), или быть написанным как часть самого main(). В частности, библиотеки, которые предназначены для использования другими программами, должны быть полностью детерминированными и не выполнять "магию инициализации".
Неудачный пример:
type Foo struct {
// ...
}
var _defaultFoo Foo
func init() {
_defaultFoo = Foo{
// ...
}
}
Более удачный пример:
var _defaultFoo = Foo{
// ...
}
// или, лучше, для тестирования:
var _defaultFoo = defaultFoo()
func defaultFoo() Foo {
return Foo{
// ...
}
}
Неудачный пример:
type Config struct {
// ...
}
var _config Config
func init() {
// Плохо: на основе текущего каталога
cwd, _ := os.Getwd()
// Плохо: I/O
raw, _ := ioutil.ReadFile(
path.Join(cwd, "config", "config.yaml"),
)
yaml.Unmarshal(raw, &_config)
}
Более удачный пример:
type Config struct {
// ...
}
func loadConfig() Config {
cwd, err := os.Getwd()
// обрабатываем err
raw, err := ioutil.ReadFile(
path.Join(cwd, "config", "config.yaml"),
)
// обрабатываем err
var config Config
yaml.Unmarshal(raw, &config)
return config
}
Учитывая вышеизложенное, некоторые ситуации, в которых init() может быть предпочтительным или необходимым, могут включать:
- Сложные выражения, которые нельзя представить как отдельные присваивания.
- Подключаемые хуки, такие как диалекты database/sql, реестры типов кодирования и т. д.
- Оптимизация Google Cloud Functions и других форм детерминированных предварительных вычислений.
Читайте также:
- Go style guides: избегайте использования встроенных имен
- Go style guides: избегайте встраивания типов в общедоступные структуры
- Спецификация Go: инициализация пакета
Комментариев нет:
Отправить комментарий