Как создавать и использовать свои собственные пакеты в Go?
Основы работы с пакетами в Go
Проблема в том, что Go использует модули и GOPATH для поиска пакетов. В современных версиях Go (1.11+) правильный способ — использовать модули. Давайте разберем пошагово.
Шаг 1: Инициализация модуля
В корне проекта (myproject/) выполните команду:
go mod init myproject
Это создаст файл go.mod с содержимым:
module myproject
go 1.21
Теперь Go знает, что ваш проект называется myproject и все импорты будут относительно этого имени.
Шаг 2: Правильная структура пакета
Пакет math должен находиться в подпапке math/. Ваш файл helpers.go уже правильный:
// math/helpers.go
package math
func Add(a int, b int) int {
return a + b
}
Важно: имя пакета (после package) должно совпадать с именем папки. В Go принято давать пакетам короткие имена (одно слово, нижний регистр).
Шаг 3: Импорт в main.go
Теперь в main.go нужно импортировать пакет с полным путем, начиная от имени модуля:
// main.go
package main
import (
"fmt"
"myproject/math" // имя_модуля/имя_папки
)
func main() {
sum := math.Add(2, 3)
fmt.Println("Сумма:", sum) // Вывод: Сумма: 5
}
Шаг 4: Экспортируемые и неэкспортируемые функции
В Go функции и переменные, начинающиеся с заглавной буквы, являются экспортируемыми (публичными). Со строчной — приватными для пакета.
// math/helpers.go
package math
// Экспортируемая функция (с большой буквы)
func Add(a int, b int) int {
return a + b
}
// Приватная функция (с маленькой буквы)
func subtract(a int, b int) int {
return a - b
}
Шаг 5: Несколько файлов в одном пакете
В одном пакете может быть много файлов. Например, создайте math/multiply.go:
// math/multiply.go
package math
func Multiply(a int, b int) int {
return a * b
}
Теперь в main.go можно использовать обе функции:
sum := math.Add(2, 3)
prod := math.Multiply(2, 3)
Шаг 6: Вложенные пакеты
Можно создавать вложенные пакеты. Например, math/advanced/:
// math/advanced/trig.go
package advanced
func Sin(x float64) float64 {
return x * 3.14 / 180 // упрощенно
}
Импорт:
import "myproject/math/advanced"
Важные правила:
- Один пакет — одна папка. Нельзя в одной папке иметь два разных пакета.
- Имя папки = имени пакета. Это конвенция, но не жесткое правило. Лучше следовать ей.
- Циклические импорты запрещены. Пакет A не может импортировать пакет B, если B импортирует A.
- Используйте
go mod tidyдля синхронизации зависимостей.
Полный рабочий пример:
myproject/
├── go.mod (module myproject)
├── main.go
└── math/
├── helpers.go (package math)
└── multiply.go (package math)
// go.mod
module myproject
go 1.21
// main.go
package main
import (
"fmt"
"myproject/math"
)
func main() {
fmt.Println(math.Add(5, 3))
fmt.Println(math.Multiply(5, 3))
}
// math/helpers.go
package math
func Add(a, b int) int { return a + b }
// math/multiply.go
package math
func Multiply(a, b int) int { return a * b }
После этого запустите go run main.go — всё должно работать!
Альтернативный подход: локальные пакеты с replace в go.mod
Если вы разрабатываете несколько проектов и хотите переиспользовать пакеты между ними, не публикуя их на GitHub, используйте директиву replace.
Пример:
У вас есть общий пакет mylib в папке ../shared/mylib:
// ../shared/mylib/strings.go
package mylib
func Reverse(s string) string {
runes := []rune(s)
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 {
runes[i], runes[j] = runes[j], runes[i]
}
return string(runes)
}
В файле go.mod вашего проекта укажите:
module myproject
go 1.21
require mylib v0.0.0
replace mylib => ../shared/mylib
Теперь можно импортировать:
import "mylib"
func main() {
fmt.Println(mylib.Reverse("привет"))
}
Преимущества:
- Не нужно копировать код между проектами.
- Изменения в
mylibсразу доступны всем проектам. - Можно использовать для временных или внутренних библиотек.
Недостатки:
- Сложнее деплоить — нужно либо копировать папку, либо публиковать модуль.
- Может возникнуть путаница с версиями.
Этот подход удобен для монолитов или микросервисов в рамках одного репозитория.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги