Avatar ·

Как избавиться от ошибки "declared and not used" в Go?

Всем привет! Я начал изучать Go недавно, и меня постоянно бесит одна ошибка. Пишу простой код, например: ```go package main import "fmt" func main() { result := calculateSum(5, 7) fmt.Println("Hello, world!") } func calculateSum(a, b int) int { sum := a + b return sum } ``` И получаю: `result declared but not used`. Ну ок, я убрал присваивание: ```go calculateSum(5, 7) ``` Но теперь ошибка: `calculateSum declared but not used` — хотя я её вызываю! А если я хочу просто протестировать функцию, не используя результат? Или когда я пишу код на скорую руку и ещё не знаю, куда пристроить переменную? Особенно бесит, когда я объявляю переменную для будущего использования, а компилятор ругается, и приходится писать `_ = result`. Это же костыль какой-то! Почему 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 // Будет использовано в следующей итерации

Это честнее, чем удалять присваивание и потом забыть, что вы что-то вычисляли.