Как избавиться от ошибки "declared and not used" в Go?
Почему Go так строг?
Ошибка "declared and not used" — это не баг, а фича языка. Разработчики Go намеренно сделали компилятор строгим, чтобы предотвратить распространённые ошибки:
- Забытые переменные, которые должны были использоваться, но остались мёртвым кодом
- Опечатки, когда вы объявили одну переменную, а используете другую
- Лишние вычисления, которые только замедляют программу
Это дисциплинирует код и делает его чище. Но для начинающих это реально бесит. Давайте разберём все легальные способы решения.
1. Использование пустого идентификатора _
Это самый простой и правильный способ, когда результат действительно не нужен:
package main
import "fmt"
func main() {
_ = calculateSum(5, 7) // Результат нас не интересует
fmt.Println("Hello, world!")
}
func calculateSum(a, b int) int {
return a + b
}
Но вы правы — это выглядит как костыль. Однако в Go _ — это полноценная часть языка, а не хак. Он явно говорит читателю: "я знаю, что тут есть значение, но оно мне не нужно".
2. Игнорирование возвращаемых значений без присваивания
Если функция возвращает только одно значение, вы можете просто не присваивать его:
calculateSum(5, 7) // Так тоже работает!
Ваш пример с calculateSum(5, 7) не сработал, потому что у вас функция возвращает значение. В Go вы не можете просто вызвать функцию, которая возвращает значение, не присвоив его. Но если функция ничего не возвращает — можно:
func printSum(a, b int) {
fmt.Println(a + b)
}
func main() {
printSum(5, 7) // Ок, функция void
}
3. Использование именованных возвращаемых значений (редко)
Если вы внутри функции, можно использовать именованный return:
func calculateSum(a, b int) (sum int) {
sum = a + b
return // sum будет возвращён автоматически
}
Но это не решает проблему на стороне вызывающего кода.
4. Подавление ошибки для целого блока (не рекомендуется)
Можно использовать комментарий //nolint для линтера, но это не отключает ошибку компилятора:
//nolint:unused
result := calculateSum(5, 7)
Это работает только если вы используете линтер (например, golangci-lint), но компилятор всё равно выдаст ошибку.
5. Лучшая практика: структурируйте код
Часто проблема в том, что вы пишете код "на вырост". Вместо того чтобы объявлять переменные заранее, объявляйте их прямо перед использованием:
func main() {
fmt.Println("Hello, world!")
// Когда понадобится — тогда и объявим
result := calculateSum(5, 7)
fmt.Println("Sum:", result)
}
Если вы пишете тестовый код — используйте тесты (*_test.go), там таких ограничений нет.
Итог
Запомните три правила:
- Если функция возвращает значение — либо присвойте его, либо используйте
_ - Если функция ничего не возвращает — вызывайте без присваивания
- Не объявляйте переменные "на будущее" — Go не прощает мёртвый код
Со временем вы привыкнете и даже полюбите эту строгость — она реально спасает от глупых багов.
<<Альтернативный подход: используйте отладку и тесты
Если вы часто пишете код для экспериментов и забываете использовать переменные, возможно, вы используете не тот инструмент. Вместо main() для тестирования используйте Go-тесты:
// main_test.go
package main
import "testing"
func TestCalculateSum(t *testing.T) {
result := calculateSum(5, 7)
// Компилятор не ругается, даже если result не используется
// Но лучше всё-таки проверить:
if result != 12 {
t.Errorf("Expected 12, got %d", result)
}
}
В тестовых файлах (*_test.go) компилятор Go не требует использовать все объявленные переменные. Это официальное послабление для тестов.
Также можно использовать Go Playground (play.golang.org) для быстрых экспериментов — там нет строгих линтеров, и вы можете спокойно тестировать код.
И наконец, если вы пишете прототип и точно знаете, что переменная понадобится позже — используйте _ с комментарием:
_ = result // Будет использовано в следующей итерации
Это честнее, чем удалять присваивание и потом забыть, что вы что-то вычисляли.