MiddleДебаггингИногдаЕщё не отвечали
Почему этот load всегда возвращает nil-ошибку, даже когда parse падает?
Этот load должен возвращать ошибку parse при сбое парсинга, но всегда возвращает вызывающему nil-ошибку.
func load() (*Config, error) {
cfg := &Config{}
if data, err := read(); err == nil {
cfg, err = parse(data)
_ = err
}
return cfg, nil
}
Найдите ошибку и объясните причину.
Функция жёстко возвращает return cfg, nil, поэтому ошибка из parse проглатывается. Родственная классика — cfg, err := parse(data) с := во вложенной области, что затеняет внешний cfg, и распарсенное значение теряется. Исправление — возвращать ошибку при сбое и избегать случайного :=; go vet это ловит.
- ✗Жёстко писать
return cfg, nilвместо возврата настоящей ошибки - ✗Использовать
:=во вложенной области, молча затеняя внешнюю переменную - ✗Считать, что ветка
ifтолько для успеха означает, чтоparseне может упасть
- →Как
:=решает, создать новую переменную или переиспользовать внешнюю? - →Что покажет анализ затенения
go vetна этой функции?
Оглавление
Найдите ошибку
func load() (*Config, error) {
cfg := &Config{}
if data, err := read(); err == nil {
cfg, err = parse(data) // тонкость := против = ниже
_ = err
}
return cfg, nil // ОШИБКА: всегда возвращает nil-ошибку
}
Почему ошибка теряется
Две связанные проблемы:
- Проглоченная ошибка. Функция безусловно возвращает
return cfg, nil. Даже еслиparseвернул ошибку, она присвоена локальномуerr, помечена_ = errи забыта — наружу всегда уходитnil.
- Затенение через
:=. Классический родственный баг — написатьcfg, err := parse(data)(с:=) во вложенной области. Поскольку слева есть новая переменная (errизif),:=создаёт новыйcfg, затеняющий внешний. Распарсенный конфиг попадает в локальную тень и теряется при выходе изif.
✅ Исправление — пробрасывать ошибку и не затенять:
func load() (*Config, error) {
data, err := read()
if err != nil {
return nil, err
}
cfg, err := parse(data)
if err != nil {
return nil, err
}
return cfg, nil
}
go vet и golangci-lint (проверка shadow) ловят затенение.
Оглавление