Импорт локальных пакетов в Go: пошаговое руководство с кодом

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Почему импорт локальных пакетов в Go вызывает столько вопросов?

Если вы когда-нибудь пытались организовать код на Go в отдельные файлы и папки, то наверняка сталкивались с ошибкой вроде could not import "myproject/utils". Это одна из самых частых проблем у начинающих Go-разработчиков. На Stack Overflow вопрос "How to import local packages in go?" набрал тысячи просмотров — и неспроста.

В отличие от Python, где достаточно просто положить файл рядом и написать import mymodule, Go требует чёткой структуры и правильной настройки модулей. Но, освоив этот механизм однажды, вы поймёте, насколько он элегантен. Давайте разберёмся раз и навсегда.

Краткая теория: как Go понимает пакеты

Прежде чем писать код, запомните три ключевых принципа:

  • Go — это язык с жёсткой модульной структурой. Каждый каталог — это один пакет (package).
  • Имя пакета не обязано совпадать с именем папки, но так делать настоятельно рекомендуется для читаемости.
  • Импорт локальных пакетов с 2019 года делается через модули (Go modules). Забудьте про GOPATH — используйте go mod.

Теперь перейдём к практике.

Шаг 1: Создаём проект с модулем

Откройте терминал и создайте новую папку для вашего проекта:

mkdir go-local-imports
cd go-local-imports

Теперь инициализируйте модуль. Имя модуля может быть любым, но логично использовать путь, который будет уникальным (например, ссылка на репозиторий):

go mod init github.com/ваш-username/go-local-imports

После этой команды в папке появится файл go.mod. Именно он будет управлять зависимостями — и локальными, и внешними.

Шаг 2: Создаём локальный пакет

Создадим папку utils внутри проекта. Внутри неё — файл math.go:

mkdir utils
cd utils
touch math.go

Откройте utils/math.go и напишите:

package utils

// Add возвращает сумму двух целых чисел
func Add(a, b int) int {
    return a + b
}

Обратите внимание: функция Add написана с большой буквы. В Go это означает, что она экспортируется (публичная). Если написать add — она будет приватной и недоступна из других пакетов.

Шаг 3: Импортируем и используем локальный пакет

Вернёмся в корневую папку проекта и создадим main.go:

cd ..
touch main.go

Содержимое main.go:

package main

import (
    "fmt"
    "github.com/ваш-username/go-local-imports/utils"
)

func main() {
    result := utils.Add(3, 5)
    fmt.Println("Сумма:", result)
}

Теперь запустите программу:

go run main.go

Вы должны увидеть:

Сумма: 8

Всё работает! Но если вы получили ошибку — читайте следующий раздел.

Типичные ошибки и их решение

Ошибка 1: "package is not in GOROOT"

Вы видите что-то вроде:

package myproject/utils is not in GOROOT (/usr/local/go/src/myproject/utils)

Причина: Вы пытаетесь импортировать пакет без модуля. Go ищет его в стандартной библиотеке, а не в вашем проекте.

Решение: Убедитесь, что в корне проекта есть go.mod. Если нет — выполните go mod init имя-модуля.

Ошибка 2: "undefined: utils.Add"

Причина: Функция написана с маленькой буквы (приватная), или вы импортировали пакет, но не используете его имя.

Решение: Проверьте, что все нужные функции экспортируются (с большой буквы), и что вы обращаетесь к ним через имя пакета: utils.Add(), а не просто Add().

Ошибка 3: "could not import" при использовании вложенных папок

Если у вас структура utils/helpers/, импорт должен быть полным:

import "github.com/ваш-username/go-local-imports/utils/helpers"

Имя пакета в файле utils/helpers/some.go должно быть package helpers.

Лучшие практики для работы с локальными пакетами в Go

  • Используйте осмысленные имена для пакетов. Избегайте названий вроде misc или common — они ничего не говорят о содержимом.
  • Не создавайте циклические зависимости. Пакет A не может импортировать пакет B, если B уже импортирует A. Go выдаст ошибку компиляции.
  • Держите пакеты маленькими. Один пакет — одна ответственность. Это облегчает тестирование и повторное использование.
  • Используйте go mod tidy. Эта команда автоматически удалит неиспользуемые зависимости и добавит недостающие:
go mod tidy

Продвинутый пример: структура реального проекта

Представьте, что вы пишете веб-сервер. Вот как может выглядеть структура папок:

myapi/
├── go.mod
├── main.go
├── handlers/
│   └── user.go
├── models/
│   └── user.go
├── database/
│   └── postgres.go
└── config/
    └── config.go

Файл config/config.go:

package config

var Port = ":8080"

Файл handlers/user.go:

package handlers

import (
    "myapi/config"
    "myapi/models"
)

func GetUser() {
    // используем config.Port и models.User
}

В main.go импорт будет выглядеть так:

import (
    "myapi/config"
    "myapi/handlers"
    "myapi/models"
)

Обратите внимание: мы не указываем полный URL с github.com, если проект не будет опубликован. Для локальной разработки достаточно имени модуля из go.mod.

Альтернативный способ: replace directive

Иногда нужно использовать локальную версию пакета, который находится в

Блоги

Рекомендаций по книгам