Материал подготовлен командой Simple-Server для администраторов VPS и выделенных серверов. Команды и пути проверяйте на тестовой машине перед production.
Кратко о задаче
В языке Go есть только циклы for. Никаких while и do while, как в некоторых других языках. Похожие концепции реализованы с помощью того же for. Это сделано для того, чтобы код был более читабельным. Разработчикам не нужно думать о том, какую стратегию выбрать. Если нужно многократно выполнить какие-то действия, есть for, который можно использовать по-разному.
Давайте посмотрим, как создавать циклы для решения некоторых задач.
Структура кода у ForClause простая. Он состоит из условия и тела. Код, который находится в теле, выполняется, если состояние равно true.
for i := 0; i < 6; i++ {
fmt.Println(i)
}Здесь i := 0 — это инициирующий оператор. Он говорит, откуда начинать выполнять loop. Дальше идет i < 6. Это состояние. Если оно равно True, код внутри цикла for**** выполняется. Конструкция fmt.Println(i) последовательно выводит цифры от 0 до 5. Каждый раз цифра увеличивается на 1 — это задано постоператором i++.
Логика простая. Код начинает выполняться с 0. 0 меньше 6, состояние равно True. На экране отображается 0. Дальше срабатывает постоператор i++, который прибавляет к текущему значению i единицу: 0 + 1 = 1. 1 меньше 6, состояние равно True. Теперь отображается 1, срабатывает постоператор i++. Дальше i = 2 (1 + 1) — продолжается выполнение одной и той же работы.
Так будет продолжаться до тех пор, пока i не станет равным 6. В таком случае состояние перестанет быть равным True, потому что 6 не меньше 6. Число 6 на экран не выводится. Функция завершает работу.
Необязательно начинать с нуля и заканчивать заданным значением. For в Go**** позволяет гибко управлять логикой решения задачи.
Величина инициирующего оператора может быть любой. Шаг постоператора тоже настраивается. Например, вы можете начать со 100 и выводить каждое десятое число:
for i := 100; i < 150; i = i + 10 {
fmt.Println(i)
}150 уже не выводится. Но если немного изменить условие, то вы получите и это число тоже:
for i := 100; i <= 150; i = i + 10 {
fmt.Println(i)
}В условии появился один дополнительный знак — равно. Теперь True возвращается, если i меньше или равно 150. Поэтому вывод изменился. Конструкция отрабатывает и при i = 150.
Вы увидите такой результат:
Таких циклов ForClause можно придумать бесконечное количество. Например, вы можете выполнять итерацию в обратном порядке — от конца к началу. Для этого нужно изменить условие и постоператор.
for i := 50; i > 0; i -= 10 {
fmt.Println(i)
}Здесь отсчет начинается с i = 100. На каждой итерации происходит проверка, что i больше 0. Пока это условие выполняется, от текущего i вычитается 10.
Цифра 0 уже не выводится, потому что в условии указано, что i должно быть больше: i > 0.
Если вы уберете из синтаксиса инициирующий оператор и постоператор, то получите простую конструкцию с состоянием, при котором она работает. Объявление цикла в таком случае будет выглядеть так:
i := 0
for i < 6 {
fmt.Println(i)
i++
}Если вы знакомы с другими языками программирования, то наверняка узнали в таком подходе работу while.
В этом примере вы определяете i за пределами конструкции.**** У синтаксиса for остается только требование — выполнять код, пока i меньше 6. Обратите внимание — та операция, которую вы указывали в качестве постоператора в предыдущих примерах (i++), теперь находится внутри тела.
В некоторых случаях количество итераций заранее неизвестно. Из-за этого вы не можете указать условие, при невыполнении которого loop будет завершен. Чтобы это не приводило к бесконечной работе, Go-циклы поддерживают ключевое слово break. Рассмотрим его работу на простом примере:
func main() {
i := 0
for {
fmt.Println("Hello")
if i == 5 {
break
}
i++
}
}Сначала вы задаете i = 0. Затем запускаете loop, который каждый раз выводит приветствие. Это продолжалось бы бесконечно, если бы вы не задали условие прекращения работы. После пятой итерации, когда i станет равно 5, сработает break и программа остановится.
Для решения повторяющихся задач в Go есть еще один тип loop — RangeClause. Он очень похож на ForClause, но по умолчанию возвращает два значения: индекс элемента и значение элемента.
Проще посмотреть на примере:
package main
import "fmt"
func main() {
words := []string{"time", "web", "Simple-Server", "cloud"}
for i, word := range words {
fmt.Println(i, word)
}
}
0 time
1 web
2 Simple-Server
3 cloudЧтобы убрать индекс, используйте вместо i пустой идентификатор. Он обозначается символом нижнего подчеркивания:
package main
import "fmt"
func main() {
words := []string{"time", "web", "Simple-Server", "cloud"}
for _, word := range words {
fmt.Println(word)
}
}RangeClause также можно использовать для добавления элементов в список:
package main
import "fmt"
func main() {
words := []string{"time", "web", "Simple-Server", "cloud"}
for range words {
words = append(words, "great")
}
fmt.Printf("%q\n", words)
}
["time" "web" "Simple-Server" "cloud" "great" "great" "great" "great"]В этом примере вы добавили элемент "great" каждому элементу длины среза words.
Ещё одно применение range — заполнение среза значениями. Допустим, у вас есть срез, состоящий из 10 нулей. Необходимо заполнить его цифрами от 0 до 9. Код:
package main
import "fmt"
func main() {
integers := make([]int, 10)
fmt.Println(integers)
for i := range integers {
integers[i] = i
}
fmt.Println(integers)
}
[0 0 0 0 0 0 0 0 0 0]
[0 1 2 3 4 5 6 7 8 9]И еще один пример — использование range для получения доступа к каждому символу внутри строки:
package main
import "fmt"
func main() {
Simple-Server := "Simple-Server"
for _, letter := range Simple-Server {
fmt.Printf("%c\n", letter)
}
}Создать цикл for можно внутри другой конструкции. Тогда он станет вложенным. На псевдокоде его синтаксис можно представить следующим образом:
for {
[Action]
for {
[Action]
}
}Сначала запускается внешний loop. Он выполняется и запускает внутренний loop. После выполнения внутренней конструкции программа возвращается наверх. Процедура повторяется до тех пор, пока сохраняется заданное состояние или не срабатывает оператор break.
Здесь тоже существует опасность создать бесконечный круг, для работы которого не хватит даже мощностей Simple-Server — он просто никогда не завершится. Чтобы не допустить этого, не забывайте проверять состояние или используйте оператор break.
Проще всего понять концепцию вложенности на примере:
package main
import "fmt"
func main() {
numList := []int{1, 2}
alphaList := []string{"a", "b", "c"}
for _, i := range numList {
fmt.Println(i)
for _, letter := range alphaList {
fmt.Println(letter)
}
}
}После выполнения этой программы вы получите:
Это отличная демонстрация порядка выполнения операций. Сначала выводится первое значение из первого списка — 1. Затем отрабатывает внутренняя конструкция, которая выводит содержимое строки "a", "b", "c". Затем программа возвращается в начало и снова выводит цифру из списка — на этот раз 2. Следующий шаг — повторная печать строки "a", "b", "c".
Нужен сервер для практики? Закажите VPS на Simple-Server — root-доступ, NVMe, DDoS-защита и поддержка 24/7.