#12 golang Цикл for (единственный на все случаи ;) range, break и особенности использования
Primary tabs
Forums:
Другие циклы нам не нужны ;)
В Go цикл представлен только одной конструкцией for, но она может принимать совершенно разные формы.
Пустой for
Есть конструкция, когда у вас нет условия — бесконечный цикл. Это аналог while(true) либо for (;;;):
// цикл без условия, while(true) OR for(;;;)
for {
fmt.Println("Без break не закончится")
break
}
-- в этом случае этот цикл нужно прервать самостоятельно. Для этого используется конструкция break.
Одна логическая проверка
Следующий вид — цикл с одиночным условием. То есть цикл будет выполняться до тех пор, пока это условие истинно:
// цикл c одиночным условием, while(isRun)
// цикл c одиночным условием, while(isRun)
isRun := 2 > 1
for isRun {
fmt.Println("Не закочим, если не поменяем значение")
isRun = false // или break
}
- понятно, что и тут break поможет выйти тоже.
Классический for из Си
Третьим вариантом цикла является классический for из Си с тремя блоками, когда вы указываете:
- блок инициализации,
- блок с условием
- и блок, который выполняется после итерации цикла.
Например:
// цикл с условием и блоком инициализации
for i := 0; i < 3; i++ {
fmt.Println("Итерация номер", i)
}
continue - переход к следующему витку цикла
Чтобы не выпонять тело цикла до конца в каком-то из витков, можно использовать continue:
// цикл с условием и блоком инициализации
for i := 0; i < 3; i++ {
fmt.Println("Итерация номер", i)
if i == 1 {
fmt.Println("Пропускаем", i)
continue
}
fmt.Println("Без continue", i)
}
Итерации по перечислимым типам
Циклы, конечно же, можно использовать для перебора разных "списков" (в общем смысле этого слова), например по схеме проверки одного условия (аналоги while в других языках) перебрать слайс:
// ручная по slice
sl := []int{1, 2, 3}
idx := 0
for idx < len(sl) {
fmt.Println("Индекс:", idx, "Значение:", sl[idx])
idx++ // Накручиваем счетчик
}
-- можно переписать в более классическом, for-подобном стиле (относительно других языков):
// ручная по slice
sl := []int{1, 2, 3}
for i := 0; i < len(sl); i++ {
fmt.Println("Индекс/значение", i, sl[i])
}-- тут мы работаем счетчиками в заголовке цикла, но всё равно это ручная работа, в других языках бывает что-то более автоматическое (как foreach в PHP), в go для этого есть range.
range для перебора списочных типов
Мы можем получать как только индексы и потом уже работать с ними:
sl := []int{1, 2, 3}
// перебор индексов
for index := range sl {
fmt.Println("Индекс: ", index, " Значение: ", sl[index])
}
так и сразу получать и индекс и значение для каждого элемента списочного типа (чтобы не обращаться по индексу явно):
sl := []int{1, 2, 3}
// перебор индексов и значений
for index, value := range sl {
fmt.Println("Индекс: ", index,
" Значение: ", value)
}
Интерация по мапам: Неопределенность порядка элементов в хэш-таблицах
ВАЖНО: в отображениях не определен порядок ключей (а значит и порядок, следования соответствующих им элементом).
Это значит, что в разных запусках программы ключи в памяти во внутренней структуре map могут располагаться совершенно по-разному из-за особенностей реализации.
Не ожидайте, что ключи будут в map ровно в том порядке, в котором вы их добавляли.
Ну а чисто позитивным моментом является то, что ассоциативные массивы также прекрасно перебираются с помощью range:
userData := map[string]string{
"name": "Vasily",
"lastName": "Romanov",
}
for key, val := range userData {
fmt.Println("Ключ Значение", key, val)
}
// или можно только по значению:
for _, val := range userData {
fmt.Println("Значение", val)
}
Итерация по строкам
Под капотом строка является слайс-байтом, но range для строки определен отдельно.
Если итерироваться по строке по значению типа string, то мы будем перебирать не байты, а полноценные отдельные символы.
В том, что возвращает range для строки, будет: позиция (номер), на которой находится символ
и непосредственно символ (руна), который представляет собой utf-ный символ:
str := "Привет, Мир!"
for pos, char := range str {
fmt.Printf("Символ %#U на позиции %d\n", char, pos)
}
Выход из цикла внутри switch
Ранее мы обсуждали работу оператора switch case.
Теперь посмотрим, как мы можем выйти из цикла в одном из case вариантов, для этого нам потребуется метка:
userData := map[string]string{
"name": "Vasily",
"lastName": "Romanov",
}
Metka: // помечаем блок
// из которого может захотим выйти
for key, val := range userData {
println("Проверяем: ", key, val)
switch {
case key == "lastName":
println("Выходим тут")
break
case key == "firstName" && val == "Vasily":
println("Выходим там")
break Metka // целимся в метку
}
} // конец for
-- в примере специально использован новгородский английский, чтобы показать, что название метки может быть любым незарезервированым словом. В последнем примере цикле перебирались ключи и значения хэш-таблицы
Видео-материалы
- Log in to post comments
- 72 reads