Как создавать циклы for в Go

Введение

В программировании компьютеров цикл (loop) — это структура кода, которая повторяет выполнение отрезка кода до тех пор, пока не будет выполнена какая-либо условие. Использование циклов в программировании позволяет автоматизировать и повторять схожие задачи множество раз. Представьте себе, что у вас есть список файлов, который нужно обработать, или что вы хотитесчитать количество строк в статье. Вы используете цикл в вашем коде, чтобы решить такие проблемы.

В языке Go цикл for реализует повторяемое выполнение кода на основе счетчика цикла или переменной цикла. В отличие от других языков программирования с множеством конструкций цикла, таких как while, do и т. д., у Go есть только цикл for. Это помогает сделать ваш код более ясным и читабельным, так как вы не должны озаботиться множеством стратегий для достижения одного и того же конструкта цикла. Эта улучшенная читабельность и снижение нагрузки на внимание durante el desarrollo также сделает ваш код менее склонным к ошибкам, чем в других языках.

В этой учебнике вы узнаете, как работает цикл for в Go, включая три основные варианта его использования. Мы начнем с показания того, как создавать различные типы циклов for, затем узнаете, как работать со секвенциальными типами данных в Go. Мы закончим тем, что объясним, как использовать вложенные циклы.

Декларирование ForClause и циклов с условием

Чтобы учитывать различные сценарии использования, в Go существуют три различных способа создания циклов for, каждый из которых обладает своими уникальными возможностями. Это создание цикла for с условием, с ForClause или с RangeClause. В этом разделе мы поясним, как декларировать и использовать варианты ForClause и условия.

Первым посмотрим, как мы можем использовать цикл for с ForClause.

Цикл ForClause определяется тем, что он состоит из первого statement, затем из условия и затем из последнего statement. Эти элементы располагаются в следующем синтаксисе:

for [ Initial Statement ] ; [ Condition ] ; [ Post Statement ] {
    [Action]
}

Чтобы объяснить, что делают предшествующие компоненты, посмотрим на цикл for, который увеличивает значение по指定的му range значений с использованием синтаксиса ForClause:

for i := 0; i < 5; i++ {
	fmt.Println(i)
}

Разберём этот цикл и идентифицируем каждую его часть.

Первая часть цикла – это i := 0. Это первое statement:

for i := 0; i < 5; i++ {
	fmt.Println(i)
}

Она утверждает, что мы декларируем переменную с именем i и устанавливаем исходное значение в 0.

Далее идёт условие:

for i := 0; i < 5; i++ {
	fmt.Println(i)
}

В этом условии мы указали, что пока i меньше значения 5, цикл должен продолжать свой цикл.

В конечном итоге мы имеем statement после цикла:

for i := 0; i < 5; i++ {
	fmt.Println(i)
}

В посте заявления мы увеличиваем циклическую переменную i на единицу при каждом выполнении итерации с использованием оператора i++ увеличения.

Когда мы запускаем этот program, выход выглядит так:

Output
0 1 2 3 4

Цикл работал 5 раз.Initially, он установил i в 0, затем проверил, был ли i меньше 5. Since значение i было меньше 5, цикл был выполнен и действие fmt.Println(i) было выполнено. После завершения цикла, пост заявление i++ было вызвано, и значение i было увеличено на 1.

注意: Remember that in programming we tend to start at index 0, that’s why although 5 numbers are printed out, they range from 0-4.

Мы не ограничены началом с 0 или окончанием с заданным значением. Мы можем присвоить любое значение нашему исходному заявлению, и также остановиться на любом значении в пост заявлении. Это позволяет нам создавать любой желаемый диапазон для цикла:

for i := 20; i < 25; i++ {
	fmt.Println(i)
}

Here, the iteration goes from 20 (inclusive) to 25 (exclusive), so the output looks like this:

Output
20 21 22 23 24

We can also use our post statement to increment at different values. This is similar to step in other languages:

First, let’s use a post statement with a positive value:

for i := 0; i < 15; i += 3 {
	fmt.Println(i)
}

In this case, the for loop is set up so that the numbers from 0 to 15 print out, but at an increment of 3, so that only every third number is printed, like so:

Output
0 3 6 9 12

Мы также можем использовать отрицательное значение для аргумента выражения последовательности для итерации в обратном порядке, но при этом нам придётся соответственно адаптировать исходный выражение и условие:

for i := 100; i > 0; i -= 10 {
	fmt.Println(i)
}

В этом контексте мы устанавливаем i в начальное значение 100, используем условие i < 0 для остановки в 0, а post-выражение уменьшает значение на 10 с помощью оператора -=.цикл начинается с 100 и заканчивается на 0, уменьшая значение на 10 с каждой итерации. Это можно увидеть в выводе:

Output
100 90 80 70 60 50 40 30 20 10

Вы также можете исключить исходное выражение и post-выражение из синтаксиса for, и использовать только условие. Это называется условием цикла:

i := 0
for i < 5 {
	fmt.Println(i)
	i++
}

В этом случае мы объявляем переменную i отдельно от цикла for на предыдущей строке кода. Цикл имеет только условие, проверяющее, является ли i меньше 5. до тех пор, пока условие оценивается как true, цикл продолжает итерации.

В некоторых случаях может быть неизвестно, сколько итераций вам потребуется, чтобы выполнить определённую задачу. В этом случае можно пропустить все выражения и использовать ключевое слово break, чтобы вывести выполнение:

for {
	if someCondition {
break
}
	// делаем действие здесь
}

Пример такого может быть, если мы читаем из неограниченного размера структуры, такой как буфер, и мы не знаем, когда мы закончим читать:

buffer.go
package main

import (
	"bytes"
	"fmt"
	"io"
)

func main() {
	buf := bytes.NewBufferString("one\ntwo\nthree\nfour\n")

	for {
		line, err := buf.ReadString('\n')
		if err != nil {
			if err == io.EOF {

				fmt.Print(line)
				break
			}
			fmt.Println(err)
			break
		}
		fmt.Print(line)
	}
}

В предшествующем коде buf :=bytes.NewBufferString("one\ntwo\nthree\nfour\n") объявляет буфер с некоторыми данными. TЬcause мы не знаем, когда буфер закончит чтение, мы создаем цикл for без условия. Внутри цикла for мы используем line, err := buf.ReadString('\n') для чтения строки из буфера и проверки, была ли ошибка при чтении из буфера. Если она была, мы обращаемся с ошибкой и используем ключевое слово break, чтобы выйти из цикла for. С помощью这些 break точек вы не нужны включать условие, чтобы остановить цикл.

В этом разделе мы узнали, как объявлять цикл ForClause и использовать его для итерации по известному диапазону значений. Мы также узнали, как использовать цикл Condition для итерации до выполнения определенного условия.次に、 мы узнаем, как использовать RangeClause для итерации по последовательным типам данных.

Итерация по последовательным типам данных с RangeClause

В Go общепринято использовать циклы for для итерации по элементам последовательных или коллекционных типов данных, таких как slices, arrays и strings. Чтобы это сделать легче, мы можем использовать цикл for с синтаксисом RangeClause. хотя вы можете проходить по последовательным типам данных, используя синтаксис ForClause, RangeClause является более чистым и более читабельным.

Перед тем, как мы посмотрим на использование RangeClause, посмотрим, как мы можем итерационно пройтись по слайсу, используя синтаксис ForClause:

main.go
package main

import "fmt"

func main() {
	sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

	for i := 0; i < len(sharks); i++ {
		fmt.Println(sharks[i])
	}
}

Выполняя это, мы получим следующий результат, выводя на экран каждый элемент слайса:

Output
hammerhead great white dogfish frilled bullhead requiem

Теперь попробуем выполнить те же действия с помощью RangeClause:

main.go
package main

import "fmt"

func main() {
	sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

	for i, shark := range sharks {
		fmt.Println(i, shark)
	}
}

В этом случае мы печатаем каждую запись в списке. хотя мы использовали переменные i и shark, мы могли бы назвать переменную любым другим верным именем переменной и получить тот же результат:

Output
0 hammerhead 1 great white 2 dogfish 3 frilled 4 bullhead 5 requiem

При использовании range с слайсом, она всегда возвращает два значения. первое значение будет индексом, на который указывает текущая итерация цикла, а второе – значением, находящимся на этом индексе. в этом случае, для первой итерации индекс был 0, а значение – hammerhead.

Иногда мы только что и хотим значение внутри элементов слайса, а не индекс. Если мы изменим предшествующий код, чтобы печатать только значение, мы получим ошибку компиляции:

main.go
package main

import "fmt"

func main() {
	sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

	for i, shark := range sharks {
		fmt.Println(shark)
	}
}
Output
src/range-error.go:8:6: i declared and not used

Поскольку i объявлен в цикле for, но никак не используется, компилятор respond with the error of i declared and not used. This is the same error that you will receive in Go any time you declare a variable and don’t use it.

По этой причине в Go есть blank identifier, который представляет собой подчеркнутый знак (_). В цикле for вы можете использовать пустой идентификатор, чтобы проигнорировать любое значение, возвращенное с помощью ключевая слова range. В этом случае мы хотим проигнорировать индекс, который является первым аргументом возвращаемого значения.

main.go
package main

import "fmt"

func main() {
	sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

	for _, shark := range sharks {
		fmt.Println(shark)
	}
}
Output
hammerhead great white dogfish frilled bullhead requiem

Этот вывод показывает, что цикл for прошел по слайсу строк и printed each item from the slice without the index.

Вы также можете использовать range для добавления элементов в список:

main.go
package main

import "fmt"

func main() {
	sharks := []string{"hammerhead", "great white", "dogfish", "frilled", "bullhead", "requiem"}

	for range sharks {
		sharks = append(sharks, "shark")
	}

	fmt.Printf("%q\n", sharks)
}
Output
['hammerhead', 'great white', 'dogfish', 'frilled', 'bullhead', 'requiem', 'shark', 'shark', 'shark', 'shark', 'shark', 'shark']

Здесь мы добавили строку-заменитель "shark" для каждого элемента длины слайса sharks.

Обратите внимание, что мы не обязаны использовать пустой идентификатор _, чтобы проигнорировать какие-либо возвращаемые значения от оператора range. Go позволяет нам опустить всю часть объявления утверждения range, если мы не нужны использовать ни одно из возвращаемых значений.

Мы также можем использовать оператор range для заполнения значений слайса:

main.go
package main

import "fmt"

func main() {
	integers := make([]int, 10)
	fmt.Println(integers)

	for i := range integers {
		integers[i] = i
	}

	fmt.Println(integers)
}

Примеры использования функции range для обработки последовательных данных будут рассмотлены в этой части статьи. Первым примером является инициализация списка integers с пустыми значениями, но цикл for перебирает все индексы списка и устанавливает все значения в список так:

Output
[0 0 0 0 0 0 0 0 0 0] [0 1 2 3 4 5 6 7 8 9]

При первом вызове функции print значение списка integers, мы видим все нули. Затем мы проходим по каждому индексу и установляем значение на текущий индекс. Тогда, когда мы печатаем значение integers второй раз, получаем, что все значения теперь равны 0 от 0 до 9.

Можно также использовать оператор range для перебора каждого символа в строке:

main.go
package main

import "fmt"

func main() {
	sammy := "Sammy"

	for _, letter := range sammy {
		fmt.Printf("%c\n", letter)
	}
}
Output
S a m m y

Когда используем цикл foreach над мапом, range вернёт как ключ, так и значение:

main.go
package main

import "fmt"

func main() {
	sammyShark := map[string]string{"name": "Sammy", "animal": "shark", "color": "blue", "location": "ocean"}

	for key, value := range sammyShark {
		fmt.Println(key + ": " + value)
	}
}
Output
color: blue location: ocean name: Sammy animal: shark

Примечание: 重要的是要注意,range每次运行时返回的顺序都是随机的。因此,每次运行这个程序你可能会得到不同的结果。

На сей раз мы научились работать с циклами внутри циклов. Теперь рассмотрим как использовать циклы внутри циклов.

Построенные изломы

Лопы могут быть применены в Go так же, как и в других языках программирования. Привязка это когда мы имеем одну конструкцию внутри другой. В случае сложными циклами имеется цикл, который выполняется внутри другого цикла. Это может бытьUseful, когда требуется выполнить действие по всему набору данных.

Построенные подобно к условиям, которые присутствуют внутри других условий. Они строится так:

for {
    [Action]
    for {
        [Action]  
    }
}

Програма первым образом столкнулась с внешним циклом, выполнив первую итерацию. Эта первая итерация запустила внутренний, сложный цикл, который затем выполнился до конца. Только после того, как программа вернулась на начало внешнего цикла, она выполнила второй итерацию и снова запустила внутренний цикл. Так же, внутренний цикл выполнился до конца, и программа вернулась на начало внешнего цикла, пока сеquence не будет завершена или прерван break или другим состоянием.

Давайте реализуем пример нисходящего for цикла, чтобы получить ближе рассмотку. В этом примере, внешний цикл будет итератором массива整数, называемый numList, а внутренний цикл будет итератором массива символов, называемый alphaList.

main.go
package main

import "fmt"

func main() {
	numList := []int{1, 2, 3}
	alphaList := []string{"a", "b", "c"}

	for _, i := range numList {
		fmt.Println(i)
		for _, letter := range alphaList {
			fmt.Println(letter)
		}
	}
}

Когда мы запускаем этот программ, мы получим следующий вывод:

Output
1 a b c 2 a b c 3 a b c

Результат приведет к тому, что программа выполнила первую итерацию внешней подходящей функции, выводя 1, который затем вызывает завершение внутренней подходящей функции, выводя a, b, c последовательно. Однако после того, как внутренняя функция была завершена, программа возвращается на начало внешней функции, выводит 2, а затем снова вызывает все содержания внутренних подходящих функций (a, b, c), и так далее.

Последовательности, составленные из порций, могут бытьUseful for iterating through items within slices. In a slice composed of slices, if we use just one for loop, the program will output each internal list as an item:

main.go
package main

import "fmt"

func main() {
	ints := [][]int{
		[]int{0, 1, 2},
		[]int{-1, -2, -3},
		[]int{9, 8, 7},
	}

	for _, i := range ints {
		fmt.Println(i)
	}
}
Output
[0 1 2] [-1 -2 -3] [9 8 7]

In order to access each individual item of the internal slices, we’ll implement a nested for loop:

main.go
package main

import "fmt"

func main() {
	ints := [][]int{
		[]int{0, 1, 2},
		[]int{-1, -2, -3},
		[]int{9, 8, 7},
	}

	for _, i := range ints {
		for _, j := range i {
			fmt.Println(j)
		}
	}
}
Output
0 1 2 -1 -2 -3 9 8 7

When we use a nested for loop here, we are able to iterate over the individual items contained in the slices.

Конслэйн

В этой уроке мы научились какdeclare and use for loops to solve for repetitive tasks in Go. We also learned the three different variations of a for loop and when to use them. To learn more about for loops and how to control the flow of them, read Working with Loops in Go: Using Break and Continue Statements.

Source:
https://www.digitalocean.com/community/tutorials/how-to-construct-for-loops-in-go