Пакеты, тестирование, файлы и JSON

Собственные пакеты: структура папок, exported и unexported имена

Содержание курса

Импорт собственного пакета по пути модуля, блок import и циклическая зависимость

Путь импорта собственного пакета строится из двух частей: имя модуля из go.mod плюс путь подпапки относительно корня модуля. Если в go.mod написано module example.com/myapp, а пакет лежит в папке mathutil/, то импорт выглядит так:

import "example.com/myapp/mathutil"

После этого к exported-именам обращаются через имя пакета: mathutil.Add(2, 3). Имя, которое используется в коде — это именно package-имя из файла, не имя папки и не последний сегмент пути (хотя обычно они совпадают).

Когда нужно импортировать несколько пакетов, их группируют в блок:

import (
    "fmt"

    "example.com/myapp/mathutil"
)

Пустая строка между стандартными и собственными пакетами — общепринятое соглашение, goimports расставляет её автоматически. Если импортированный пакет нигде не используется, компилятор отказывается собирать программу — неиспользованный импорт запрещён.

Циклическая зависимость. Представим, что пакет api импортирует пакет storage, а storage решает импортировать api — например, чтобы использовать какой-то тип оттуда. Go-компилятор немедленно останавливается:

import cycle not allowed

Циклы запрещены полностью, без исключений. Решение зависит от причины цикла.

Если цикл возник из-за общего типа или константы, которая нужна обоим пакетам, — такой код выносят в третий пакет, например models, который не импортирует ни api, ни storage. Тогда оба пакета импортируют только models, и цикл исчезает:

 api  →  models
          ↑
storage →

Этот приём работает именно тогда, когда общий код действительно независим и имеет смысл как отдельная единица.

В других ситуациях решение иное: иногда стоит пересмотреть направление зависимости — перенести ответственность в один из пакетов, чтобы второй больше не нуждался в обратном импорте. Иногда два тесно связанных пакета имеет смысл объединить в один. Универсального рецепта нет: цикл — это сигнал, что границы между пакетами стоит пересмотреть.