Глиф Учебники

Урок 4. Условия, switch и цикл for

Курс «Go» · урок 4 из 10 · 4 минуты чтения

В других языках есть while, do … while, тернарный оператор ?:. В Go всё проще: условия — if и switch, цикл — только for, но в нескольких формах.

if и else

Go
package main

import "fmt"

func main() {
    score := 74
    if score >= 90 {
        fmt.Println("отлично")
    } else if score >= 70 {
        fmt.Println("хорошо")
    } else {
        fmt.Println("нужно подтянуть")
    }
}
Вывод
хорошо

Условия проверяются сверху вниз, выполняется только первый подошедший блок. Правила записи:

Сравнения: ==, !=, <, <=, >, >=. Логические операции: && (и), || (или), ! (не). Условие должно быть именно bool: if n для числа n не соберётся, нужно if n != 0.

Тернарного оператора условие ? a : b в Go нет — пишут обычный if.

if с коротким объявлением

Перед условием можно объявить переменную — она будет видна только внутри if и его else:

Go
package main

import "fmt"

func main() {
    price, discount := 120, 15
    if total := price - discount; total > 100 {
        fmt.Println("бесплатная доставка, сумма", total)
    } else {
        fmt.Println("доставка платная, сумма", total)
    }
}
Вывод
бесплатная доставка, сумма 105

Чаще всего так проверяют ошибки: if err := сделать(); err != nil { … } — об этом в уроке Функции и ошибки.

switch

switch сравнивает значение с вариантами по порядку. В отличие от C и Java, break в конце варианта не нужен: выполняется только один case.

Go
package main

import "fmt"

func main() {
    day := "сб"
    switch day {
    case "пн", "вт", "ср", "чт", "пт":
        fmt.Println("рабочий день")
    case "сб", "вс":
        fmt.Println("выходной")
    default:
        fmt.Println("нет такого дня")
    }

    t := 15
    switch {
    case t < 0:
        fmt.Println("мороз")
    case t < 20:
        fmt.Println("прохладно")
    default:
        fmt.Println("тепло")
    }
}
Вывод
выходной
прохладно

Если нужно, чтобы после варианта выполнился и следующий, пишут fallthrough — нужно это редко:

Go
package main

import "fmt"

func main() {
    switch n := 1; n {
    case 1:
        fmt.Println("один")
        fallthrough
    case 2:
        fmt.Println("два")
    case 3:
        fmt.Println("три")
    }
}
Вывод
один
два

fallthrough переходит в следующий case, не проверяя его условие, и только на один шаг: до "три" дело не дошло.

day := "сб" switch day { case "пн", "вт", "ср", "чт", "пт": case "сб", "вс": выходной default: не проверяется после switch break не нужен: выполняется один case switch n := 1; n { case 1: один fallthrough case 2: два без проверки case 3: не выполняется после switch fallthrough — ровно на один шаг
В switch выполняется только первый подошедший case, и сразу идёт выход — break не нужен; fallthrough без проверки переходит ровно в следующий case, а case 3 уже не выполняется.

Цикл for

Классическая форма — три части через точку с запятой: начало, условие, шаг:

Go
package main

import "fmt"

func main() {
    sum := 0
    for i := 1; i <= 5; i++ {
        sum += i
    }
    fmt.Println("сумма от 1 до 5:", sum)
}
Вывод
сумма от 1 до 5: 15

Переменная i видна только внутри цикла. Скобок вокруг трёх частей нет, фигурные скобки обязательны.

for i := 1; i <= 5; i++ { начало условие шаг i := 1 i <= 5 да sum += i i++ нет выход i i <= 5 sum 1 да 1 2 да 3 3 да 6 4 да 10 5 да 15 6 нет выход
Цикл for i := 1; i <= 5; i++ один раз выполняет начало, затем проверяет условие, выполняет тело sum += i и шаг i++; при i = 6 условие ложно, и цикл заканчивается с sum = 15.

for вместо while

Если оставить одно условие, получится цикл «пока» — как while в других языках:

Go
package main

import "fmt"

func main() {
    n := 2024
    digits := 0
    for n > 0 {
        digits += n % 10
        n /= 10
    }
    fmt.Println("сумма цифр:", digits)
}
Вывод
сумма цифр: 8

n % 10 — последняя цифра числа, n /= 10 отбрасывает её. Цикл идёт, пока цифры не кончатся.

Без условия совсем — бесконечный цикл for { … }. Из него выходят командой break или return.

break и continue

break прерывает цикл, continue пропускает остаток текущего шага и переходит к следующему:

Go
package main

import "fmt"

func main() {
    for i := 1; ; i++ {
        if i%2 == 0 {
            continue
        }
        if i > 7 {
            break
        }
        fmt.Println(i)
    }
}
Вывод
1
3
5
7

Здесь у цикла нет условия (между точками с запятой пусто), поэтому он закончится только на break.

Во вложенных циклах break выходит только из внутреннего. Чтобы выйти сразу из обоих, у внешнего цикла ставят метку:

Go
package main

import "fmt"

func main() {
outer:
    for i := 1; i <= 3; i++ {
        for j := 1; j <= 3; j++ {
            if i*j == 4 {
                break outer
            }
            fmt.Println(i, j)
        }
    }
    fmt.Println("готово")
}
Вывод
1 1
1 2
1 3
2 1
готово

Как только i*j стало равно 4 (при i = 2, j = 2), оба цикла закончились. continue outer так же переходит к следующему шагу внешнего цикла.

outer: for i := 1; i <= 3; i++ for j := 1; j <= 3; j++ if i*j == 4 fmt.Println(i, j) break outer выход из обоих просто break — к следующему i fmt.Println("готово") вывод 1 1 1 2 1 3 2 1 i=2, j=2 2*2 == 4 готово
При i = 2 и j = 2 команда break outer выходит сразу из обоих циклов к строке с «готово», а обычный break вышел бы только из внутреннего цикла — к следующему i.

for range

range перебирает элементы: числа от нуля, буквы строки, элементы срезов и map. С Go 1.22 можно перебирать и просто число:

Go
package main

import "fmt"

func main() {
    for i := range 3 {
        fmt.Println("повтор", i)
    }

    for i, r := range "Го!" {
        fmt.Println(i, string(r))
    }
}
Вывод
повтор 0
повтор 1
повтор 2
0 Г
2 о
4 !

range 3 даёт 0, 1, 2. У строки range выдаёт пару: номер байта, с которого начинается символ, и сам символ (rune). Русская буква занимает два байта, поэтому номера идут 0, 2, 4. Срезы и map перебираются так же — это в следующих уроках.

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

Коротко

Проверьте себя

1. Как в Go записать цикл «пока n > 0»?
2. Что выведет программа?
Go
package main

import "fmt"

func main() {
    x := 2
    switch x {
    case 1:
        fmt.Println("один")
    case 2:
        fmt.Println("два")
    case 3:
        fmt.Println("три")
    }
}
3. Сколько раз выполнится тело цикла for i := range 5?
4. Как выйти сразу из двух вложенных циклов?