Какое правило Go определяет, доступно ли имя из другого пакета?
Доступность определяется регистром первой буквы идентификатора: имя, начинающееся с заглавной Unicode-буквы, экспортируется и доступно из другого пакета; имя со строчной буквы остаётся непубличным. Это правило применяется к функциям, типам, переменным, константам, методам и полям структур.
Пакеты в Go одновременно группируют код и формируют границы его публичного API. Явное правило на основе регистра заменяет отдельные ключевые слова вроде public и private, уменьшая синтаксическую сложность языка.
Такой подход делает видимость заметной непосредственно в объявлении. Разработчик сразу видит, какие элементы предназначены для использования за пределами пакета, а какие являются внутренней реализацией.
Если случайно экспортировать внутреннее поле или функцию, внешний код начнёт зависеть от детали реализации. Последующее переименование или изменение типа может потребовать исправлений во всех потребителях.
Обратная ошибка тоже возможна: непубличное имя нельзя напрямую использовать из другого пакета, даже если сам пакет импортирован. Поэтому публичный API часто строят через экспортированный конструктор или метод, скрывая внутреннее состояние.
Идентификатор экспортируется, если его первая буква является заглавной Unicode-буквой. Например, User, NewUser, ID и Name доступны через селектор другого пакета, а user, name и validate — нет.
Правило относится именно к имени, а не к месту вызова. Псевдоним импорта, вложенность, указатель или способ получения значения не делают непубличное имя доступным. Импортированный пакет также не получает доступа к внутренностям другого пакета через обходные обращения.
Для полей структуры видимость проверяется отдельно для каждого поля. Структура может иметь экспортированный тип и одновременно скрытые поля; это позволяет запретить внешнему коду произвольное создание состояния через составной литерал и контролировать его изменение методами.
Экспортированный метод может быть объявлен у непубличного типа. Внешний пакет не сможет назвать тип напрямую, но иногда сможет работать с полученным значением через экспортированный метод или интерфейс. Это полезно для сокрытия конкретной реализации.
Пример:
Внешний пакет может обратиться к model.User, model.NewUser, u.ID и u.Name(), но не к u.name. При этом метод Name предоставляет контролируемый способ чтения скрытого поля.
Библиотека хранит в структуре сетевого клиента адрес сервера, таймаут и внутреннее состояние соединения. Вариант с экспортированными полями прост для использования, но позволяет клиентскому коду записать несовместимые значения и усложняет изменение реализации.
Вариант со всеми непубличными полями лучше защищает инварианты, но требует экспортированного конструктора и методов доступа. Это добавляет небольшой объём API, зато библиотека контролирует проверку аргументов и может изменить внутреннее представление без изменения пользовательского кода.
Разумное решение — экспортировать тип, конструктор и необходимые методы, а состояние оставить непубличным. В результате некорректные состояния создаются реже, а граница ответственности между библиотекой и её пользователем становится явной.
Нет. Псевдоним импорта меняет только локальное имя, используемое для обращения к пакету. Он не меняет исходное имя объявления и не влияет на правило экспортируемости.
A до Z?Нет. Go учитывает заглавные буквы Unicode, поэтому идентификатор может быть экспортирован, если начинается с заглавной буквы другого алфавита. На практике для публичного API обычно используют ASCII-имена, поскольку они лучше читаются и совместимы с общепринятыми соглашениями.
Да, если внешнему коду каким-либо способом доступно значение этого типа, например через экспортированную функцию или интерфейс. Сам непубличный тип нельзя корректно указать в исходном коде другого пакета как имя типа, но его экспортированные методы могут участвовать во взаимодействии; это позволяет скрывать конкретную реализацию за публичным контрактом.