Модуль - это дерево пакетов. Имя модуля задаётся в go.mod
Модули и пакеты как каталоги с файлами
Пакет - это набор исходных .go файлов, находящихся в одном каталоге и с одинаковой директивой package
.
Файлы для одного пакета обязаны находиться в одном каталоге. Полное имя для пакета строится из имени модуля и пути к каталогу с файлами. Например,
- в
go.mod
написано module example.org/mylib
,
- тогда все пакеты из модуля
example.org/mylib
должны быть в дочерних каталогах относительно go.mod
.
- и путь к каталогу определяет имя пакета.
Например, в дереве исходников вашей библиотеки есть файлы в каталоге ./cmd/root
. Тогда эти файлы должны быть либо с директивой package root
, либо package root_test
. И полное имя пакета для этих файлов будет либо example.org/mylib/cmd/root
, либо example.org/mylib/cmd/root_test
[1].
Области видимости в модулях и пакетах
Имена, начинающиеся с маленькой буквы, видны только в пакете. Другие пакеты, даже в том же самом модуле, не имеют доступа к этим сущностям.
Примеры. В пакете example.org/mylib/cmd/root
объявлены:
- структура
type struct myCommand
. Эту структуру можно использовать только в коде, относящемуся к package root
.
- глобальная переменная
var flagConfig = "config"
так же видна лишь в пакете root
. Аналогично с именами функций и методов.
- поле структуры
type struct Stuff { buf []byte ... }
: структура Stuff
видна всем, кто импортирует пакет example.org/mylib/cmd/root
, но только внутри пакета root
можно обращаться к полю buf
. (на самом деле до поля buf
можно добраться через рефлексию, но это совершенно другая история)
Пакеты, содержащие /internal/
внутри пути, видны только в модуле. Никакой другой модуль не может использовать объявения из этих пакетов. Попробуйте как-нибудь вызывать функцию edwards25519.NewScalar()
из пакета crypto/internal/edwards25519
и полюбуйтесь на ошибку компиляции could not import crypto/internal/edwards25519
Поиск пакетов
Поиск пакетов в сети
Для автоматического поиска пакетов в Гугле придумали протокол goproxy
Он реализован в GitHub, поэтому любой модуль, размещённый там, автоматически будет найден командами go get
, go mod tidy
, go build
и подобными.
Но никто не ограничивает вас пользоваться только гитхабом. К примеру, поддержка goproxy есть в GitLab. Разворачиваете у себя на сервере гитлаб, настраиваете домены и прокси - и готово, go get
начинает находить модули с вашим доменным именем.
Поиск пакетов в файловой системе
replace
Можно развернуть исходники стороннего модуля у себя в файловой системе, а в go.mod
прописать зависимость с replace
:
require example.org/some/module v1.01.02
replace example.org/some/module => ../some_module_src
В этом случае go build
вообще не полезет в интернет, а возьмёт исходники модуля example.org/some/module
из каталога ../some_module_src
Workspace
Воркспейс позволяет находить модули в соседних каталогах.
Например, вы создаёте приложение в модуле example.org/myapp
и используете библиотеку example.org/mylib
. Понятное дело, что автоматический поиск пакетов не может обнаружить example.org/mylib
, ибо в домене example.org
отсутствует Go прокси.
При этом вам не хочется уродовать свой go.mod
инструкцией replace
. Тогда создайте каталог workspace
, в нём два подкаталога - workspace/myapp
и workspace/mylib
. В myapp
поместите исходники приложения, а в mylib
исходники библиотеки. Затем в каталоге workspace
выполните команды
go work init
go work use ./mylib
go work use ./myapp
и вуаля! магия воркспейсов заработала. Теперь пакет с именем example.org/mylib/root/cmd
будет найден в каталоге workspace/mylib/root/cmd
.
[1] Пакет example.org/mylib/cmd/root_test
должен содержать тесты для пакета example.org/mylib/cmd/root