Функция объявлена в другом файле, но Go пишет "undefined": что делать?
Проблема: запуск одного файла вместо всего пакета
Ваша ошибка типична для новичков в Go. Вы запускаете go run main.go, но компилятору Go нужно передавать все файлы пакета, которые участвуют в сборке. Когда вы указываете только main.go, Go пытается скомпилировать и запустить только этот файл, не видя math.go, где объявлена функция add.
Решение: передайте все файлы или используйте go run с маской
Есть несколько способов исправить ситуацию:
Способ 1: Передать все файлы явно
go run main.go math.go
Способ 2: Использовать маску для всех .go файлов
go run *.go
Способ 3 (рекомендуемый): Собрать и запустить пакет целиком
go run .
Команда go run . компилирует и запускает весь текущий пакет (все файлы с package main в текущей директории). Это самый правильный подход.
Почему так происходит?
В Go единицей компиляции является пакет, а не отдельный файл. Компилятор go build или go run сначала собирает все файлы с одинаковым package в одной директории, затем компилирует их вместе. Если вы явно перечисляете файлы, Go не ищет другие файлы в папке — он использует только то, что вы указали.
Важный нюанс: все файлы в одной директории обязаны иметь одинаковый package (в вашем случае package main). Исключение — тестовые файлы с суффиксом _test, которые могут быть в том же пакете, но компилируются отдельно.
Дополнительные советы
- Для больших проектов используйте
go buildдля компиляции, а затем запускайте бинарник:go build -o myapp . && ./myapp. - Если вы используете IDE (VS Code с Go-расширением, GoLand), они обычно автоматически запускают
go run .при нажатии кнопки Run. - Проверяйте, что в папке нет других файлов с несовместимыми пакетами — это вызовет ошибку компиляции.
Пример рабочего запуска
После исправления ваш проект будет работать:
$ go run .
Результат: 8
Также можно использовать go run main.go math.go — это тоже сработает, но менее удобно при большом количестве файлов.
Альтернативный подход: разделение на пакеты
Хотя ваша проблема решается простым запуском go run ., на будущее рекомендую структурировать код с использованием отдельных пакетов. Это улучшит организацию проекта и сделает его более модульным.
Пример: создайте папку math и поместите туда файл с функцией:
// math/math.go
package math
func Add(a int, b int) int {
return a + b
}
Затем в main.go импортируйте этот пакет:
package main
import (
"fmt"
"your-module/math"
)
func main() {
result := math.Add(5, 3)
fmt.Println("Результат:", result)
}
Обратите внимание: функция Add начинается с заглавной буквы — это обязательно для экспорта из пакета. В Go экспортируются только идентификаторы, начинающиеся с большой буквы.
Такой подход:
- Избегает путаницы с файлами в одном пакете.
- Позволяет переиспользовать код в других проектах.
- Соответствует лучшим практикам Go-сообщества.
Для небольших программ (например, учебных) достаточно просто запускать go run ., но при росте проекта рекомендую переходить на пакеты.