golang #2.1 Пакеты и модули - чем они отличаются

Что такое Пакет

Пакеты (packages) — это основная единица организации кода, по сути это папки с .go файлами, определяемые package имя)

Что такое Модуль

Модули (modules) — это коллекции пакетов (то есть в модуль могут входить много папок), которые управляют зависимостями, версионированием и распространением всего проекта (или его части) с помощью файла go.mod (этот файл создается первый раз при инициллизации модуля, что требуется в т.ч. для запуска минимальной программы)

Таким образом:

  • пакеты это просто папки с файлами,
  • а модули — это "библиотека" или же конечное "приложение", в котором может быть несколько собственных пакетов.

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

Представим проект myapp — это один модуль (корневая папка с файлом go.mod), внутри которого лежат несколько пакетов (папок с .go-файлами):

myapp/                // корневая папка = модуль
├── go.mod            // файл модуля - создаётся при go mod init
├── main.go           // .go-файлы в корне тоже образуют пакет (main)
├── utils/            // пакет utils
│   └── strings.go
└── math/             // пакет math
    └── calc.go

Файл go.mod задаёт имя (путь) модуля и версию языка, например:

module myapp

go 1.21

здесь module myapp — путь модуля, а go 1.21 — минимальная версия языка, под которую написан код.

Как модуль связан с импортом собственных пакетов

Путь импорта своего пакета складывается из пути модуля из go.mod и расположения папки пакета внутри проекта, например в main.go:

package main

import (
	"fmt"

	"myapp/utils" // свой пакет: путь модуля + имя папки
)

func main() {
	fmt.Println(utils.Reverse("привет"))
}

то есть "fmt" — пакет из стандартной библиотеки, а "myapp/utils" — наш собственный пакет, путь к которому начинается именно с той строки, которая объявлена в go.mod после слова module.

Важные правила

Одна папка = один пакет — все .go-файлы в одной папке обязаны объявлять одно и то же имя пакета (строкой package имя в начале файла), иначе программа не скомпилируется.

Имя пакета обычно совпадает с именем папки (utils/ → package utils) — это соглашение, а не требование языка. Имена пакетов принято писать коротко и строчными буквами, без подчёркиваний и camelCase.

Пакет main — особый: только он собирается в исполняемую программу, и именно с его функции main() начинается выполнение (подробнее об этом поговорим после).

Краткое сравнение

Пакет Модуль
Что это папка с .go-файлами весь проект (или библиотека) целиком
Чем задаётся строкой package имя в файлах файлом go.mod в корневой папке
Сколько бывает в одном модуле — сколько угодно один на проект
Для чего нужен организация кода, переиспользование, границы видимости имён зависимости, версионирование, сборка и распространение

Откуда берутся пакеты при импорте

Пакеты в импортах могут приходить из трёх источников:

  1. Стандартная библиотека — идёт вместе с компилятором: "fmt", "strings", "math".
  2. Собственные пакеты модуля — просто папки внутри нашего проекта, как "myapp/utils" выше.
  3. Внешние модули — чужой код из интернета, который подключается командой go get.

При подключении внешнего модуля (пункт 3) в go.mod появляется блок require с версией, а рядом с ним создаётся файл go.sum с контрольными суммами зависимостей:

module myapp

go 1.21

require github.com/google/uuid v1.6.0

Подробнее про создание модуля: см. заметку Инициализация модуля - go mod init.

Key Words for FKN + antitotal forum (CS VSU):