У if в Go нет круглых скобок вокруг условия, фигурные скобки обязательны всегда, а перед условием можно поставить короткую инструкцию, объявляющую переменные с областью видимости внутри if.
Условия проверяются сверху вниз, и выполняется первая истинная ветка. else if и else необязательны.
Правила синтаксиса
Три правила отличаются от C, Java и JavaScript:
- Никаких круглых скобок вокруг условия.
if (x > 5)скомпилируется, ноgofmtскобки уберёт. - Фигурные скобки обязательны, даже для одной инструкции. Формы без скобок вроде
if x > 5 returnнет. 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. Повторение это цена того, что каждая точка отказа видна там, где она возникает.