Структура Go-проекта: пакеты, модули и организация кода

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

В этом уроке изучаем базовую организацию Go-проекта: как правильно структурировать файлы и папки, работать с пакетами, создавать модули и понимать, как файлы взаимодействуют друг с другом. Разбираем соглашения об именовании и учимся управлять видимостью функций.

Ключевые концепции

Naming conventions в Go

Go использует специфичный стиль именования файлов — camelCase без явных разделителей. В отличие от других языков:

  • Python: user_service.py (snake_case)
  • JavaScript: user-service.js (kebab-case)
  • Java: UserService.java (PascalCase)
  • C#: UserService.cs (PascalCase)
  • Go: userservice.go или createCatalogItemResult.go (camelCase слитно)

Важно: Go не требует префикса get для геттеров. Вместо GetOwner() пишем просто Owner().

Package (пакет)

Пакет — это способ группировки связанного кода в Go. Каждый .go файл начинается с декларации пакета:

package main

Правила работы с пакетами:

  • Все файлы в одной директории должны принадлежать одному пакету
  • package main — специальный пакет для исполняемых программ (не библиотек)
  • Для библиотек используются другие имена пакетов

Функция main

Точка входа в программу — функция main() внутри пакета main:

package main

func main() {
    // код программы
}

Особенности:

  • Должна быть объявлена в пакете main
  • Не принимает параметров
  • Не возвращает значений (в отличие от C/C++)
  • Go runtime автоматически вызывает её при запуске
  • Если нужно завершить программу с кодом ошибки: os.Exit(1)

Модули (go modules)

Модуль — это коллекция связанных пакетов с версионированием. Создаётся командой:

go mod init github.com/username/projectname

Создаёт файл go.mod, который описывает модуль и его зависимости.

Практика

Базовая структура файла

Минимальная программа Hello World:

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
}

Быстрый способ добавления импортов: Не нужно вручную писать import "fmt" — начните печатать fp и нажмите Enter. VS Code автоматически добавит:

fmt.Println()

И сам импортирует пакет при сохранении файла.

Запуск программы

Из терминала:

# Перейти в директорию с файлом
cd src/day001

# Запустить программу
go run app.go

Работа с несколькими файлами в одном пакете

Создаём второй файл second.go в той же директории:

package main

func hello() {
    fmt.Println("Hello2")
}

Используем в app.go:

package main

import "fmt"

func main() {
    fmt.Println("Hello, World!")
    hello() // функция из second.go
}

Важно: При запуске нужно указать все файлы:

go run app.go second.go

Или проще — все файлы в директории:

go run .

Создание отдельного пакета

Структура проекта:

golang-master-course/
├── go.mod
└── src/
    └── day001/
        ├── app.go          (package main)
        ├── second.go       (package main)
        └── mathmod/
            └── utils.go    (package mathmod)

Создаём модуль в корне проекта:

go mod init github.com/username/golang-master-course

Файл mathmod/utils.go:

package mathmod

func Calculate() {
    // какая-то логика
}

Обратите внимание: функция Calculate начинается с заглавной буквы — это делает её экспортируемой (публичной).

Импорт собственного пакета

В app.go:

package main

import (
    "fmt"
    "github.com/username/golang-master-course/src/day001/mathmod"
)

func main() {
    fmt.Println("Hello, World!")
    mathmod.Calculate()
}

После сохранения VS Code автоматически отформатирует импорты.

Запуск:

go run .

Видимость (экспорт) в Go

В Go нет ключевых слов public/private. Видимость определяется регистром первой буквы:

Экспортируемые (публичные) — начинаются с заглавной буквы:

func Calculate() { } // доступна вне пакета
type User struct { } // доступна вне пакета
var MaxCount = 100   // доступна вне пакета

Неэкспортируемые (приватные) — начинаются со строчной буквы:

func calculate() { } // доступна только внутри пакета
type user struct { } // доступна только внутри пакета
var maxCount = 100   // доступна только внутри пакета

Важные моменты

1. Пробелы в именах Избегайте пробелов в именах директорий и файлов — они создают проблемы при работе в терминале.

2. Стандартная библиотека Пакеты стандартной библиотеки (например, fmt, os) не требуют создания модуля — они доступны сразу.

3. Один пакет — одна директория Если у вас несколько .go файлов в одной папке — они должны объявлять один и тот же пакет.

4. Структура импортов VS Code автоматически группирует импорты при сохранении: сначала стандартные библиотеки, затем внешние зависимости, затем локальные пакеты.

5. go run . Команда go run . запускает все .go файлы в текущей директории — удобнее, чем перечислять каждый файл.

Что запомнить

  • Каждый файл начинается с package имя
  • package main + func main() = исполняемая программа
  • Файлы в одной папке = один пакет
  • go mod init создаёт модуль для работы с собственными пакетами
  • Заглавная буква = экспорт (public), строчная = приватная функция
  • go run . запускает все файлы в директории
  • Стандартная библиотека доступна без создания модуля
  • Naming: camelCase слитно, без разделителей