В Go нет ключевого слова while. Напишите for и после него условие, и получится цикл while:
Условие проверяется перед каждой итерацией, поэтому если оно ложно с самого начала, тело не выполнится ни разу. Это то же самое, что while (balance < 2000) в C, Java или JavaScript, только без скобок и ключевого слова. Создатели Go выбрали одно ключевое слово для всех видов циклов; все четыре формы разобраны на странице о цикле for.
while(true): бесконечный цикл
Уберите условие совсем, и цикл будет работать, пока что-то внутри его не завершит:
Идиоматичная запись for { }. for true { } тоже компилируется, но выглядит так, будто автор пришёл из другого языка.
Бесконечный цикл завершают четыре вещи: break (выход из цикла), return (выход из функции), паника и os.Exit. Программа, чей main крутится в for {} без всего этого, работает, пока её не убьют, и для сервера или воркера это именно то, что нужно.
do-while
do-while выполняет тело один раз, прежде чем проверить условие. Отдельного синтаксиса в Go нет. Поставьте проверку в конец бесконечного цикла:
Тело выполняется хотя бы один раз в любом случае, и это определяющее свойство do-while. Источник случайных чисел использует фиксированное зерно, поэтому вывод одинаков при каждом запуске; для настоящей случайности используйте rand.IntN без источника с зерном.
Вторая форма оставляет условие в заголовке, принудительно выполняя первый проход:
for first := true; first || condition(); first = false {
// body
}
Это работает, но бесконечный цикл с break в конце читается проще, и так делает большая часть кода на Go.
Чтение до конца
Самый частый цикл while в реальном коде на Go читает ввод, пока тот не закончится. bufio.Scanner создан для этого: Scan возвращает false в конце ввода или при ошибке, поэтому он и служит условием цикла:
Замените strings.NewReader(input) на os.Stdin, и тот же цикл будет читать ввод пользователя построчно. После цикла проверьте scanner.Err(): по false из Scan нельзя понять, закончился ввод нормально или с ошибкой.
break и continue
Оба работают в любой форме for:
В цикле только с условием continue сразу переходит к проверке условия. Отсюда легко получить тонкий баг: если счётчик обновляется внизу тела, continue выше пропускает обновление, и цикл никогда не заканчивается. Обновляйте счётчик в начале, как выше, или используйте for из трёх частей, где инструкция post выполняется и после continue.
Ожидание чего-либо
Цикл, который ждёт выполнения условия, должен блокироваться или спать, а не крутиться вхолостую:
// Wrong: burns a CPU core while waiting
for !ready {
}
// Better: poll with a delay
for !isReady() {
time.Sleep(100 * time.Millisecond)
}
Опрос обычной переменной, в которую пишет другая горутина, ещё и гонка данных. Между горутинами лучше ждать на канале, sync.WaitGroup или sync.Cond, либо использовать select с таймером. Для циклов повторных попыток с лимитом предпочитайте счётный for, чтобы цикл не мог работать вечно:
for attempt := 1; attempt <= 5; attempt++ {
if err := connect(); err == nil {
break
}
time.Sleep(time.Duration(attempt) * 200 * time.Millisecond)
}
Частые ошибки
- Условие никогда не меняется.
for i < 10 { fmt.Println(i) }не закончится никогда. В теле каждого цикла while должно быть что-то, что приближает его к выходу. - Написать
while.while x < 5 {}даётsyntax error: unexpected name x at end of statement, потому чтоwhileне ключевое слово, и компилятор читает его как обычное имя. - Скобки по привычке.
for (x < 5) {}компилируется, аgofmtубирает скобки. - Объявление переменной в цикле.
for n := 10; n > 0 {}это синтаксическая ошибка: цикл с инструкцией инициализации требует всех трёх частей. Объявитеnдо цикла или напишите полную форму из трёх частей.
Часто задаваемые вопросы
Есть ли в Go цикл while?
Как ключевого слова нет. Go использует for для всех циклов, а for с одним только условием это ровно цикл while:
for count < 10 {
count++
}
Условие проверяется перед каждой итерацией, так же как while (count < 10) в C или Java.
Как написать while(true) в Go?
Напишите for без ничего после него: for { ... }. Цикл крутится, пока его не завершат break, return, паника или os.Exit. for true { ... } тоже компилируется, но идиоматичная форма for { }.
Как написать цикл do-while в Go?
Используйте бесконечный цикл и поставьте проверку условия в конце тела:
for {
// body runs at least once
if !condition {
break
}
}
Тело всегда выполняется один раз до проверки условия, а это и есть смысл do-while.