Как правильно организовать структуру многофайлового проекта на Go?
Основная проблема: пакеты и импорты в Go
Вы столкнулись с классической ошибкой новичков. В Go код организуется через пакеты, а не просто через файлы в папках. Ваш код в tasks/tasks.go объявляет пакет package tasks, а main.go — пакет main. Чтобы использовать функции из одного пакета в другом, их нужно импортировать.
Шаг 1: Инициализируйте модуль
Go требует явного указания модуля. Это аналог package.json в Node.js или requirements.txt в Python.
go mod init todo-app
После этой команды появится файл go.mod с содержимым:
module todo-app
go 1.21
Шаг 2: Исправьте структуру папок и импорты
Ваша структура должна выглядеть так:
todo-app/
├── go.mod
├── main.go
└── tasks/
└── tasks.go
Теперь исправьте main.go:
package main
import (
"fmt"
"todo-app/tasks" // Импорт пакета tasks из модуля todo-app
)
func main() {
task := tasks.CreateTask("Купить молоко") // Обратите внимание: tasks.CreateTask
fmt.Println(task.Title)
}
А в tasks/tasks.go нужно экспортировать структуру и функцию (с большой буквы):
package tasks
type Task struct {
Title string
}
func CreateTask(title string) Task {
return Task{Title: title}
}
Шаг 3: Правила экспорта в Go
- Имена с большой буквы — экспортируются (видны из других пакетов).
- Имена с маленькой буквы — приватные (видны только внутри своего пакета).
- Ваша функция
CreateTaskэкспортируется, потому что начинается с заглавной буквы.
Полный рабочий пример
main.go
package main
import (
"fmt"
"todo-app/tasks"
)
func main() {
task1 := tasks.CreateTask("Купить хлеб")
task2 := tasks.CreateTask("Сделать ДЗ")
fmt.Printf("Задача 1: %s\n", task1.Title)
fmt.Printf("Задача 2: %s\n", task2.Title)
}
tasks/tasks.go
package tasks
import "fmt"
type Task struct {
Title string
Complete bool
}
func CreateTask(title string) Task {
return Task{Title: title}
}
func (t *Task) MarkComplete() {
t.Complete = true
fmt.Printf("Задача '%s' выполнена!\n", t.Title)
}
Дополнительные советы
- Один пакет — одна папка. Не кладите два разных пакета в одну папку.
- main.go должен быть в корневой папке проекта (не в подпапке).
- Имена пакетов обычно совпадают с именем папки (tasks → пакет tasks).
- Если файлы в одной папке, они должны иметь одинаковый package.
После всех изменений запустите:
go run main.go
Или, если хотите собрать бинарник:
go build -o todo-app
<<Альтернативный подход: всё в одном пакете, но в разных файлах
Если ваш проект небольшой (до 1000 строк) и не предполагает переиспользования кода в других проектах, можно обойтись без создания отдельных пакетов. Просто разложите код по разным файлам в одной папке с одинаковым package main.
Пример структуры:
todo-app/
├── main.go // точка входа, вызовы
├── tasks.go // структуры и функции для задач
└── storage.go // работа с файлами/БД
main.go
package main
func main() {
task := CreateTask("Купить молоко")
SaveTask(task)
}
tasks.go
package main
type Task struct {
Title string
}
func CreateTask(title string) Task {
return Task{Title: title}
}
storage.go
package main
import "fmt"
func SaveTask(t Task) {
fmt.Printf("Сохранена задача: %s\n", t.Title)
}
В этом случае не нужно импортировать — все функции и типы видны во всех файлах пакета main. Компиляция:
go run .
Когда использовать:
- Прототипирование и маленькие утилиты
- Учебные проекты
- Когда код не нужно переиспользовать
Минусы:
- Нет чёткого разделения ответственности
- Риск конфликтов имён при разрастании проекта
- Нельзя переиспользовать код в других проектах
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги