Menu

if else в Golang: синтаксис, инициализация и if err != nil

Как работают if, else if и else в Go: без скобок вокруг условия, с обязательными фигурными скобками, if с инструкцией инициализации и его область видимости, идиома if err != nil и ранний возврат вместо глубокой вложенности.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

У if в Go нет круглых скобок вокруг условия, фигурные скобки обязательны всегда, а перед условием можно поставить короткую инструкцию, объявляющую переменные с областью видимости внутри if.

Условия проверяются сверху вниз, и выполняется первая истинная ветка. else if и else необязательны.

Правила синтаксиса

Три правила отличаются от C, Java и JavaScript:

  1. Никаких круглых скобок вокруг условия. if (x > 5) скомпилируется, но gofmt скобки уберёт.
  2. Фигурные скобки обязательны, даже для одной инструкции. Формы без скобок вроде if x > 5 return нет.
  3. else пишется на той же строке, что и закрывающая скобка. Go вставляет точку с запятой после } в конце строки, поэтому такой код не работает:
if x > 5 {
	fmt.Println("big")
}
else {
	fmt.Println("small")
}
syntax error: unexpected keyword else, expected }

Пишите } else { на одной строке.

Условие должно иметь тип bool. Go не считает 0, "" или nil ложью, поэтому if count {} и if name {} не компилируются. Сравнивайте явно: if count > 0, if name != "", if user != nil.

Условия объединяются через && (и), || (или) и ! (не). И &&, и || вычисляются по короткой схеме, поэтому проверки на nil безопасны:

if user != nil && user.IsAdmin() {
	// user.IsAdmin() is only called when user is not nil
}

if с инструкцией инициализации

if может выполнить одну короткую инструкцию перед условием, отделённую точкой с запятой. Объявленные в ней переменные видны во всех ветках этого if и нигде после него:

Этот шаблон не пускает короткоживущие переменные в окружающую область видимости. Он постоянно встречается с поиском в мапе (v, ok := m[k]), утверждениями типа (s, ok := v.(string)) и ошибками.

Обратная сторона: если значение нужно после if, объявите его заранее. Частая ошибка: положить результат в инструкцию инициализации, а потом пытаться использовать его ниже.

Идиома if err != nil

Функции, которые могут завершиться ошибкой, возвращают error последним. Проверьте её сразу, обработайте или верните и продолжайте основной сценарий без дополнительного отступа:

Обратите внимание: после if err != nil { return ... } нет else. В стиле Go ошибку обрабатывают, возвращаются, а обычный поток оставляют у левого края. Оборачивание и проверка типов ошибок разобраны на странице об обработке ошибок.

Ранний возврат вместо вложенности

Глубоко вложенные блоки if трудно читать. Инвертируйте условия и возвращайтесь раньше; тогда каждая проверка читается как защитное условие:

// Nested
func canCheckout(u *User, cart *Cart) bool {
	if u != nil {
		if u.Verified {
			if len(cart.Items) > 0 {
				return true
			}
		}
	}
	return false
}

// Guards
func canCheckout(u *User, cart *Cart) bool {
	if u == nil || !u.Verified {
		return false
	}
	if len(cart.Items) == 0 {
		return false
	}
	return true
}

Go-разработчики называют это «держать основной сценарий по левому краю». Линтеры вроде revive отмечают else после блока, который заканчивается return, потому что такой else добавляет отступ впустую.

if/else или switch

Длинную цепочку else if, которая сравнивает одно значение с несколькими вариантами, лучше записать как switch. switch без выражения заменяет цепочку if/else if с произвольными условиями:

switch {
case score >= 90:
	return "A"
case score >= 80:
	return "B"
default:
	return "F"
}

Используйте if для одной или двух веток, а switch, когда их три и больше.

Тернарного оператора нет

В Go нет cond ? a : b. Присваивайте через if:

label := "odd"
if n%2 == 0 {
	label = "even"
}

Почему так и какие есть альтернативы, объясняет страница о тернарном операторе.

Частые ошибки

  • Затенение через :=. if x, err := f(); err == nil { ... } объявляет новый x только для этого if. Внешний x не обновляется.
  • Присваивание в условии. if x = 5 {} это ошибка компиляции (cannot use assignment x = 5 as value), а не тихий баг, как в C. Используйте ==.
  • Сравнение float через ==. if total == 0.3 не срабатывает для вычисленных значений. Сравнивайте с допуском.
  • Проверка не той ошибки. После a, err := f() и b, err := g() убедитесь, что каждый if err != nil стоит сразу после своего вызова.

Часто задаваемые вопросы

Как написать if else в Go?

Без круглых скобок вокруг условия и всегда с фигурными скобками:

if x > 10 {
	fmt.Println("big")
} else if x > 5 {
	fmt.Println("medium")
} else {
	fmt.Println("small")
}

else должен стоять на той же строке, что и закрывающая скобка предыдущего блока.

Что такое if с инструкцией инициализации в Go?

Короткая инструкция перед условием, отделённая точкой с запятой: if n, err := strconv.Atoi(s); err != nil { ... }. Объявленные в ней переменные существуют только внутри if и его веток else if и else, поэтому не утекают в остальную часть функции.

Можно ли написать if в одну строку в Go?

Не без фигурных скобок. if ok return и if (ok) x = 1; это синтаксические ошибки. Самая короткая форма if ok { return }, и gofmt перенесёт тело на отдельную строку. Тернарного оператора в Go тоже нет, поэтому для условного значения нужен if/else или маленькая вспомогательная функция.

Почему в Go везде if err != nil?

В Go нет исключений. Функции, которые могут завершиться ошибкой, возвращают error последним результатом, и вызывающий код сразу проверяет его через if err != nil. Повторение это цена того, что каждая точка отказа видна там, где она возникает.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ