Представьте функцию, где имя локальной переменной совпало с именем импортированного пакета: какой идентификатор будет найден при обращении через точку?
Внутри области видимости локальная переменная затеняет имя импортированного пакета. Поэтому обращение через точку разрешается относительно переменной, а не пакета; если у её типа нет нужного метода или поля, компиляция завершится ошибкой.
Go использует лексические области видимости: значение идентификатора определяется по ближайшему подходящему объявлению. Такой подход делает разрешение имён предсказуемым и позволяет локально использовать короткие имена, не меняя объявления в других областях программы.
Имя импортированного пакета доступно в области файла, но вложенные области, включая тело функции и параметры, могут его затенить.
Затенение часто возникает случайно: например, параметр или локальная переменная получает имя fmt, json, errors или другого импортированного пакета. После этого выражение с таким идентификатором перестаёт обращаться к пакету.
Последствия — ошибка компиляции, обращение не к тому методу или дополнительное сообщение о неиспользуемом импорте. Особенно опасно это при рефакторинге, когда новое локальное имя добавляется далеко от места использования пакета.
Разрешение имени идёт от внутренней области к внешним. Если внутри функции объявлена переменная fmt, то в выражении fmt.Println сначала находится именно она; импортированный пакет с тем же именем уже не рассматривается.
В примере fmt.Println трактуется как селектор у значения строкового типа. У строки нет метода Println, поэтому код не компилируется; импорт fmt при этом фактически не используется.
Надёжное решение — выбирать локальному идентификатору другое имя. Если конфликт неизбежен, импорт можно назначить псевдониму, но и этот псевдоним способен быть затенён во вложенной области.
Важно отличать затенение от повторного объявления: локальное имя не изменяет и не удаляет импорт, а только делает его недоступным в конкретной области видимости. За пределами этой области исходное имя пакета снова разрешается нормально.
В обработчике HTTP параметр назвали json, одновременно используя пакет encoding/json. Вызов сериализации перестал разрешаться, потому что json ссылался на параметр.
Можно было переименовать импорт в stdjson или изменить имя параметра. Псевдоним импорта удобен, если параметр является частью внешнего API и менять его нельзя, но он увеличивает визуальный шум во всём файле.
Предпочтительным решением было переименовать локальный параметр в payload: это сохранило стандартное имя пакета, улучшило читаемость и устранило риск аналогичного конфликта в соседних выражениях.
Да. Параметры находятся во вложенной области видимости тела функции и имеют приоритет над именами из области файла. Поэтому параметр с именем импортированного пакета полностью меняет смысл обращений к этому имени внутри функции.
Имя импорта и объявление верхнего уровня в одном файловом блоке не могут без конфликта сосуществовать с одинаковым именем. Это не обычное затенение во вложенной области, а конфликт объявлений в одной области видимости, который компилятор отвергает.
Нет. Псевдоним, например stdjson, становится новым именем импортированного пакета и тоже может быть затенён локальной переменной или параметром stdjson. Псевдоним устраняет конкретное совпадение имён, но не отменяет правила лексического разрешения.