Avatar ·

В чем разница между операторами := и = в Go? Объясните с примерами

Привет! Я только начал изучать Go и никак не могу понять разницу между := и =. Вроде оба оператора что-то присваивают, но компилятор ругается, если я их путаю. Вот пример кода, который у меня не работает: ```go package main import "fmt" func main() { var name string name = "Alice" fmt.Println(name) // А это почему-то не компилируется: var age int age := 25 // ошибка: no new variables on left side of := fmt.Println(age) } ``` Я читал документацию, но там написано сложно. Объясните простыми словами: когда использовать :=, а когда =? И почему в одном случае я могу написать `x := 10`, а в другом `var x int = 10`? Еще меня смущает, что в некоторых примерах я вижу, как := используют внутри функций, но не на уровне пакета. Это ограничение языка? Буду благодарен за подробное объяснение с примерами, когда какой оператор применять. <<>>

Краткий ответ

:= — это короткая форма объявления и одновременно инициализации переменной. = — это просто присваивание значения уже существующей переменной. Главное правило: := можно использовать только если хотя бы одна переменная слева является новой.

Подробное объяснение

В Go есть два принципиально разных действия с переменными:

  • Объявление (declaration) — создание переменной с указанием типа
  • Присваивание (assignment) — запись значения в уже объявленную переменную

Оператор := делает сразу оба действия. Он объявляет переменную и присваивает ей значение. Тип определяется автоматически из выражения справа:

// Эквивалентные записи:
var x int = 10
var x = 10     // тип выводится автоматически
x := 10        // короткая форма — только внутри функций!

Главные отличия

ОператорДействиеГде использовать
:=Объявление + присваиваниеТолько внутри функций (включая методы)
=Только присваиваниеВезде: функции, пакет, методы

Правильные и неправильные примеры

// ✅ Правильно: объявляем новую переменную
x := 10

// ✅ Правильно: присваиваем значение существующей
x = 20

// ❌ Ошибка: x уже объявлена, нет новых переменных
x := 30

// ✅ Правильно: хотя бы одна переменная новая
x, y := 40, "hello"  // y — новая, x — существующая

// ✅ Правильно: переиспользуем переменную в цикле
for i := 0; i < 5; i++ {
    // i объявляется один раз, потом только присваивается
}

// ❌ Ошибка: := на уровне пакета
package main
version := "1.0"  // нельзя! Используйте var version = "1.0"

Почему так сделано?

:= существует для удобства — чтобы не писать var каждый раз. Но Go строг к объявлению переменных: вы не можете объявить одну и ту же переменную дважды в одной области видимости. Поэтому компилятор проверяет, что слева от := есть хотя бы одна новая переменная. Это защищает от случайного затирания значений.

Когда что использовать?

  • Используйте := для локальных переменных внутри функций, особенно когда тип очевиден
  • Используйте = для изменения значения уже существующей переменной
  • Используйте var на уровне пакета, для глобальных переменных, или когда нужно явно указать тип

Типичная ошибка новичка

func main() {
    var count int
    count := 5  // ❌ Ошибка: count уже объявлен
    
    // Правильно:
    count = 5
    
    // Или если нужно объявить сразу:
    // count := 5 (без предварительного var)
}

Запомните: := — это "объявить и присвоить", = — это "присвоить существующей". Как только переменная объявлена, используйте только =.

<<>>

Дополнительный взгляд: область видимости и теневая переменная

Есть ещё один важный нюанс, который часто путает новичков. Оператор := создаёт новую переменную в текущей области видимости, даже если переменная с таким же именем существует во внешней области:

func main() {
    name := "Alice"
    {
        name := "Bob"  // Это НОВАЯ переменная, она "затеняет" внешнюю
        fmt.Println(name) // Bob
    }
    fmt.Println(name) // Alice — внешняя не изменилась
}

С оператором = такого не произойдёт — он изменит именно ту переменную, которая доступна в текущей области:

func main() {
    name := "Alice"
    {
        name = "Bob"  // Изменяем ту же самую переменную
        fmt.Println(name) // Bob
    }
    fmt.Println(name) // Bob — значение изменилось
}

Это поведение называется "shadowing" (затенение). Оно часто становится причиной багов, когда вы думаете, что изменяете переменную, а на самом деле создаёте новую. Совет: будьте внимательны с := внутри блоков if, for и других конструкций, создающих новую область видимости.

Если сомневаетесь — используйте var и = явно. Это немного длиннее, но безопаснее для понимания кода.