Avatar ·

Функция объявлена в другом файле, но Go пишет "undefined": что делать?

Всем привет! Я только начал изучать Go и столкнулся со странной проблемой. У меня есть простой проект с двумя файлами в одной папке: **main.go:** ```go package main import "fmt" func main() { result := add(5, 3) fmt.Println("Результат:", result) } ``` **math.go:** ```go package main func add(a int, b int) int { return a + b } ``` Я запускаю `go run main.go` и получаю ошибку: ``` # command-line-arguments .\main.go:6:14: undefined: add ``` Почему Go не видит функцию `add`, которая объявлена в другом файле? Ведь оба файла находятся в одной папке и имеют одинаковый package main. Я читал, что в Go не нужно явно импортировать функции из файлов одного пакета. В чём может быть проблема? Уже перепроверил синтаксис — вроде всё правильно. Подскажите, пожалуйста, как это исправить? Буду благодарен за подробное объяснение. <<>>

Проблема: запуск одного файла вместо всего пакета

Ваша ошибка типична для новичков в 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 ., но при росте проекта рекомендую переходить на пакеты.