Введение: почему путаница между := и = может сломать ваш Go-код
Вы пишете на Go, всё идёт отлично, но вдруг компилятор выдаёт ошибку no new variables on left side of :=. Знакомо? Или вы видите код коллеги, где он использует то =, то :=, и кажется, что разницы нет. На самом деле разница принципиальная, и непонимание этого — одна из самых частых ошибок у новичков в Golang.
В этом руководстве мы разберём, чем отличаются операторы := (short variable declaration) и = (assignment). Вы узнаете, когда какой использовать, как не нарваться на ошибки и как писать более чистый и идиоматичный код на Go. Поехали!
Основы: что такое переменные и зачем они нужны?
Прежде чем нырять в дебри операторов, давайте вспомним, что переменная — это именованная область памяти, где хранится значение определённого типа. В Go, как и в любом строго типизированном языке, с переменной нужно работать аккуратно.
Операторы := и = — это два способа взаимодействия с переменными, но они решают разные задачи. Первый — объявляет переменную, второй — изменяет её значение.
Оператор = (присваивание): только изменение, без объявления
Оператор = — это классическое присваивание. Он берёт уже существующую переменную и записывает в неё новое значение. Если переменной не существует, компилятор выдаст ошибку.
package main
import "fmt"
func main() {
var name string // объявили переменную явно
name = "Go" // присвоили значение (работает)
fmt.Println(name)
// age = 10 // ОШИБКА: переменная age не объявлена
}
Здесь name была объявлена с помощью var, поэтому мы можем использовать =. Если бы мы попробовали написать age = 10 без предварительного объявления, компилятор бы отказался компилировать код.
Когда использовать =?
- Когда переменная уже объявлена (через
varили:=). - В циклах и итерациях для обновления счётчиков.
- При работе с указателями и структурами, где нужно изменить поле.
Оператор := (короткое объявление): объявление + присваивание за один шаг
Оператор := — это "синтаксический сахар", который одновременно объявляет переменную и присваивает ей значение. Тип переменной выводится автоматически из выражения справа. Это гораздо короче, чем писать var x int = 5.
package main
import "fmt"
func main() {
name := "Go" // объявили и присвоили, тип string
age := 10 // объявили и присвоили, тип int
fmt.Println(name, age)
}
Это эквивалентно:
var name string = "Go"
var age int = 10
Но := короче и читается легче. Главное правило: слева от := должна быть хотя бы одна новая переменная. Если все переменные уже объявлены, вы получите ошибку.
Когда использовать :=?
- Для объявления локальных переменных внутри функций.
- В циклах
for,ifиswitchс короткой инициализацией. - При работе с функциями, возвращающими несколько значений (например,
err := someFunc()).
Главное отличие: объявление vs изменение
Самое важное различие, которое нужно запомнить:
:=— это объявление (declaration). Оно создаёт новую переменную в текущей области видимости.=— это присваивание (assignment). Оно изменяет существующую переменную.
Попробуйте представить это как разницу между "рождением" переменной и "изменением её имени". Вы не можете изменить имя человека, которого ещё нет на свете.
Сложные случаи: несколько переменных и переобъявление
Go допускает интересный трюк: если слева от := есть хотя бы одна новая переменная, остальные могут быть уже существующими. Это называется переобъявление (redeclaration).
package main
import "fmt"
func main() {
x := 10
y := 20
// x уже существует, но z — новая. Это разрешено!
x, z := 30, 40
fmt.Println(x, y, z) // Вывод: 30 20 40
}
Здесь x получит новое значение, а z будет объявлена. Это очень удобно при работе с ошибками:
package main
import (
"fmt"
"os"
)
func main() {
file, err := os.Open("test.txt")
if err != nil {
fmt.Println(err)
return
}
// ... работаем с file
// Пытаемся открыть другой файл
otherFile, err := os.Open("other.txt") // err уже существует, но otherFile — новый
if err != nil {
fmt.Println(err)
return
}
_ = otherFile
}
Обратите внимание: err не создаётся заново, а просто перезаписывается. Это экономит память и делает код чище.
Типичные ошибки и как их избежать
Ошибка 1: Использование := с уже объявленной переменной
package main
func main() {
x := 5
x := 10 // ОШИБКА: no new variables on left side of :=
}
Решение: Используйте = для изменения x.
Ошибка 2: Использование = для несуществующей переменной
package main
func main() {
x = 5 // ОШИБКА: undefined: x
}
Решение: Объявите переменную через var или :=.
Ошибка 3: Путаница с областью видимости
package main
import "fmt"
func main() {
x := 10
if true {
x := 20 // Это НОВАЯ переменная x в области видимости if
fmt.Println(x) // 20
}
fmt.Println(x) // 10 (внешняя переменная не изменилась)
}
Здесь := внутри if создаёт новую переменную, которая "затеняет" внешнюю. Если вы хотите изменить внешнюю, используйте =.
Практические советы: как писать идиоматичный Go
-
Блоги
Рекомендаций по книгам
Читайте также
Как пройти собеседование на Python-разработчика
UIAlertView в Swift: 5 фатальных ошибок и как их избежать
Регулярные выражения в Swift: полное руководство с примерами
Code Review в Go: что проверять и как давать обраттную связь на практике
HTTP клиент на JavaScript: делаем запросы правильно от А до Я