Go: с нуля до своего блога Урок 6 из 50
Ветвление и цикл в Go: if, else и единственный for
Шестой урок курса по Go. Как программа выбирает между двумя путями: if, else if и else, сравнения и логические И, ИЛИ, НЕ. И цикл — в Go он ровно один, слово for, зато в трёх формах: со счётчиком, по условию и без условия с break. Ни while, ни do-while, ни foreach в языке нет.
Зачем это нужно
Пока ваша программа делает одно и то же независимо от значений. Чтобы отвечать по-разному — статью с тысячей просмотров назвать популярной, а со свежей десяткой новой — нужно ветвление.
А чтобы повторить действие, не переписывая его десять раз, нужен цикл. И вот здесь Go устроен непривычно: цикл в нём один. Слова while, do-while и foreach в языке отсутствуют — всё это делает for, просто в разных формах.
Сразу целиком
Новая папка, go mod init sabaq05, main.go:
package main
import "fmt"
func label(views int) string {
if views >= 1000 {
return "популярное"
} else if views >= 100 {
return "читают"
}
return "новое"
}
func main() {
fmt.Println(12, "—", label(12))
fmt.Println(340, "—", label(340))
fmt.Println(1500, "—", label(1500))
for i := 1; i <= 3; i++ {
fmt.Println("урок", i)
}
words := 0
for words < 600 {
words += 200
}
fmt.Println("накопилось слов:", words)
}
Прежде чем запускать — не заглядывая ниже, скажите вслух, что она напечатает. Потом запустите и сверьте: расхождение и есть то место, где вы ещё не знаете языка.
go run . печатает:
12 — новое
340 — читают
1500 — популярное
урок 1
урок 2
урок 3
накопилось слов: 600
Разбор
if: развилка
if views >= 1000 {
Условие пишется без круглых скобок — в Go они не нужны и их не ставят. Тело всегда в фигурных, даже если внутри одна строка: сокращённой записи без скобок в языке нет, и это избавляет от целого класса ошибок, на которых спотыкаются в других языках.
Образ. Развилка на дороге со знаком. Знак ничего не делает — он только решает, по какой стороне вы поедете дальше. Обе дороги существуют, поехать можно лишь по одной.
else if и else
Проверки идут сверху вниз, и выполняется первая подошедшая. Порядок поэтому важен: если поставить >= 100 выше >= 1000, то тысяча попадёт в «читают» и до второй проверки дело не дойдёт.
else в конце не обязателен. В примере его нет: после всех проверок стоит просто return "новое" — тот же смысл, на строку короче.
Чем сравнивают
== равно, != не равно, < > <= >=. Двойное равенство в сравнении и одинарное в присваивании — разные вещи, и Go не даст их перепутать: if views = 1000 не соберётся.
Условия соединяют: && — и то, и другое; || — хотя бы одно; ! — наоборот.
if views >= 100 && views < 1000 {
for со счётчиком
for i := 1; i <= 3; i++ {
Три части через точку с запятой: завести счётчик, пока проверять, что делать после каждого круга. i++ — увеличить на единицу.
Образ. Три вещи, которые говорят кладовщику: с какой полки начать, до какой считать и через сколько шагать. Скажете все три — он обойдёт склад сам.
for по условию
for words < 600 {
Одна часть вместо трёх. В других языках это называется while; в Go это тот же for, просто без счётчика и без шага.
for без условия
for {
// пока не скажут выйти
}
Крутится вечно, пока внутри не встретится break. Так пишут серверы и ожидание событий.
break выходит из цикла совсем. continue бросает текущий круг и начинает следующий.
Образ. Очередь.
break— уйти из очереди насовсем.continue— пропустить свой шаг и сразу перейти к следующему, не доделав то, что собирались.
if с коротким объявлением
Здесь возвращается прошлый урок. Функция отдаёт два значения, и оба нужны только внутри проверки:
if minutes, ok := readingTime(700); ok {
fmt.Println(minutes)
}
Точка с запятой отделяет объявление от условия. minutes и ok живут только внутри этого if и снаружи не существуют — а значит, не мешают и не путаются с другими именами. В Go так пишут почти всегда, когда результат нужен ровно на одну проверку.
Четвёртая форма — потом
У for есть ещё одна запись, range: она обходит то, что состоит из частей — строку по буквам, список по элементам. Со строкой встретимся уже в следующем уроке, со списком — в уроке про срезы.
Функция может позвать сама себя
Цикл — не единственный способ повторить. Функция может вызвать саму себя, и называется это рекурсией:
func countdown(n int) {
if n == 0 {
fmt.Println("поехали")
return
}
fmt.Println(n)
countdown(n - 1)
}
func main() {
countdown(3)
}
3
2
1
поехали
Здесь две части, и обе обязательны. Первая — выход: if n == 0 и return, случай, в котором функция больше себя не зовёт. Вторая — шаг, который к этому выходу приближает: countdown(n - 1), каждый раз с числом поменьше.
Уберите выход — и программа не остановится. Go не даст ей висеть вечно, но и не поблагодарит:
runtime: goroutine stack exceeds 1000000000-byte limit
fatal error: stack overflow
Каждый вызов занимает место в памяти, и когда место кончается, программа падает. Цикл for так упасть не может: он не копит вызовы.
Образ. Матрёшка. Вы открываете её, внутри такая же поменьше, и так до самой маленькой — цельной. Если бы маленькой не было, вы бы открывали до бесконечности.
Когда её выбирают вместо цикла: когда данные вложены сами в себя. Комментарий к комментарию, папка в папке, ответ на ответ — обойти такое циклом трудно, а рекурсией естественно. Для плоского списка цикл проще и быстрее, и в этом курсе почти везде будет он.
Карта урока
Скажите своими словами
Не подглядывая, ответьте вслух или на бумаге. Ответы — в конце урока.
- Почему в
labelпорядок проверок нельзя поменять местами? - Чем
breakотличается отcontinue? - Зачем писать
if n, ok := f(); ok, если можно объявитьnиokстрокой выше?
Задание
Обязательное. Напишите функцию label(views int) string: при 1000 и больше возвращает "популярное", при 100 и больше — "читают", иначе "новое". Вызовите её из main для 12, 340 и 1500 и напечатайте результат.
По желанию.
- Цикл со счётчиком от 1 до 10, который печатает только чётные числа. Подсказка: остаток от деления —
%, чётное значитi%2 == 0. - Вернитесь к заданию прошлого урока, которое ждало
if: сделайте, чтобыreadingTimeвозвращала два значения — минуты иbool, разумное ли число слов. - Цикл
forбез условия, который выходит поbreakна пятом круге.
Куда это встанет в блоге
Ветвление в блоге повсюду: показать статью или ответить 404, пустить редактировать или отказать, вывести «нет комментариев» или список. А цикл понадобится, как только статей станет больше одной, — и в уроке про срезы вы обойдёте их все одной строкой.
Ответы
Показать ответы
- Потому что выполняется первая подошедшая проверка, а не самая точная. Тысяча просмотров удовлетворяет и
>= 100, и>= 1000; если сначала стоит сотня, до тысячи дело не дойдёт и «популярное» не выпадет никогда. Условия ставят от узкого к широкому. breakзаканчивает цикл целиком, и выполнение идёт дальше за ним.continueзаканчивает только текущий круг: остаток тела пропускается, но цикл продолжается со следующего значения.- Чтобы имена не жили дольше, чем нужны. Объявленные строкой выше,
nиokостанутся до конца функции, будут мешать назвать что-то так же и создадут иллюзию, что ими можно пользоваться дальше. Вifони исчезают на закрывающей скобке.
Источники
Если вы нашли ошибку или опечатку в тексте статьи, то сообщите нам об этом
Комментарии (0)
Войдите, чтобы оставить комментарий →
Пока нет комментариев. Будьте первым.