Теперь, когда мы знаем про переменные, самое время написать что-нибудь полезное. Сначала создадим программу, которая по очереди с новой строки выводит числа от 1 до 10. Наших знаний достаточно для того, чтобы написать эту программу так:
package main
import "fmt"
func main() {
fmt.Println(1)
fmt.Println(2)
fmt.Println(3)
fmt.Println(4)
fmt.Println(5)
fmt.Println(6)
fmt.Println(7)
fmt.Println(8)
fmt.Println(9)
fmt.Println(10)
}
или так:
package main
import "fmt"
func main() {
fmt.Println(`1
2
3
4
5
6
7
8
9
10`)
}
Но писать это будет довольно утомительно, так что нам нужен лучший способ несколько раз повторить определенный набор действий.
For
Оператор for
даёт возможность повторять список инструкций (блок) определённое
количество раз. Давайте перепишем предыдущую программу, используя оператор for
:
package main
import "fmt"
func main() {
i := 1
for i <= 10 {
fmt.Println(i)
i = i + 1
}
}
Сначала создается переменная i
, хранящая число, которое нужно вывести на
экран. Затем с помощью ключевого слова for
создается цикл, указывается
условное выражение, которое может принимать значение true
или false
, и, наконец, сам блок
для выполнения. Цикл for работает следующим образом:
оценивается (выполняется) условное выражение
i <= 10
(«i меньше или равно десяти»). Если оно истинно, выполняются инструкции внутри блока. В противном случае управление переходит следующей после блока строке кода (в нашем случае после цикла ничего нет, поэтому совершается выход из программы);после запуска всех инструкций внутри блока мы возвращаемся в начало цикла и повторяем первый шаг.
Строка i = i + 1
очень важна - без неё выражение i <= 10
всегда будет true
,
и выполнение программы никогда не завершится (это называется бесконечным
циклом).
Следующий пример показывает выполнение программы точно так же, как это делает компьютер:
- создать переменную
i
со значением 1; -
i
меньше или равно10
? да; - вывести
i
; - присвоить
i
значениеi + 1
(теперь равно 2); -
i
меньше или равно10
? да; - вывести
i
; - присвоить
i
значениеi + 1
(теперь равно 3); - …
- присвоить
i
значениеi + 1
(теперь равно 11); -
i
меньше или равно10
? нет; - больше нечего делать, выходим.
В других языках программирования существуют разные виды циклов (while, do, until, foreach, …). У Go вид цикла один, но он может использоваться в разных случаях. Предыдущую программу можно также записать следующим образом:
func main() {
for i := 1; i <= 10; i++ {
fmt.Println(i)
}
}
Теперь условное значение включает в себя также и две другие инструкции,
разделенные точкой с запятой. Сначала инициализируется переменная, затем
выполняется условное выражение, и в завершении переменная «инкрементируется»
(добавление 1 к значению переменной является настолько распространённым
действием, что для этого существует специальный оператор: ++
; аналогично
вычитание 1 может быть выполнено с помощью --
).
В следующих главах мы увидим и другие способы использования циклов.
If
Давайте изменим программу так, чтобы вместо простого вывода чисел 1–10 она также указывала, является ли число чётным или нечётным. Вроде этого:
1 odd
2 even
3 odd
4 even
5 odd
6 even
7 odd
8 even
9 odd
10 even
Для начала нам нужен способ узнать, является ли число чётным или нечётным. Самый
простой способ — это разделить число на 2. Если остатка от деления не будет,
значит число чётное, иначе — нечётное. Так как же найти остаток от деления на
Go? Для этого существует оператор %
. Например:
1 % 2
равно1
;2 % 2
равно0
;3 % 2
равно1
и так далее.
Далее нам нужен способ, чтобы выполнять действия в зависимости от условия. Для этого мы
используем оператор if
:
if i % 2 == 0 {
// even
} else {
// odd
}
Оператор if
аналогичен оператору for
в том, что он выполняет блок в
зависимости от условия. Оператор также может иметь необязательную else
часть.
Если условие истинно, выполняется блок, расположенный после условия, иначе же
этот блок пропускается и выполняется блок else
, если он присутствует.
Еще условия могут содержать else if
часть:
if i % 2 == 0 {
// divisible by 2
} else if i % 3 == 0 {
// divisible by 3
} else if i % 5 == 0 {
// divisible by 5
}
Условия выполняются сверху вниз, и первое условие, которое окажется истинным, приведет в исполнение связанный с ним блок.
Собрав всё вместе, мы получим:
func main() {
for i := 1; i <= 10; i++ {
if i % 2 == 0 {
fmt.Println(i, "even")
} else {
fmt.Println(i, "odd")
}
}
}
Давайте рассмотрим эту программу:
- Создать переменную
i
типаint
и присвоить ей значение1
; -
i
меньше или равно10
? Да - перейти в блок; - остаток от
i
÷2
равен0
? Нет - переходим к блокуelse
; - вывести
i
вместе сodd
; - инкрементировать
i
(оператор после условия); -
i
меньше или равно10
? Да - перейти в блок; - остаток от
i
÷2
равен0
? Да - переходим к блокуif
; - вывести
i
вместе сeven
; - …
Оператор деления с остатком (деление по модулю), который редко можно увидеть за пределами начальной школы, оказывается действительно полезным при программировании. Он будет встречаться везде - от раскрашивания таблиц зеброй до секционирования наборов данных.
Switch
Предположим, мы захотели написать программу, которая печатала бы английские названия для чисел. С использованием того, что мы знали до текущего момента, это могло бы выглядеть примерно так:
if i == 0 {
fmt.Println("Zero")
} else if i == 1 {
fmt.Println("One")
} else if i == 2 {
fmt.Println("Two")
} else if i == 3 {
fmt.Println("Three")
} else if i == 4 {
fmt.Println("Four")
} else if i == 5 {
fmt.Println("Five")
}
Но эта запись слишком громоздка. Go содержит в себе другой оператор, позволяющий
делать такие вещи проще: оператор switch
(переключатель). С ним программа
может выглядеть так:
switch i {
case 0: fmt.Println("Zero")
case 1: fmt.Println("One")
case 2: fmt.Println("Two")
case 3: fmt.Println("Three")
case 4: fmt.Println("Four")
case 5: fmt.Println("Five")
default: fmt.Println("Unknown Number")
}
Переключатель начинается с ключевого слова switch
, за которым следует выражение
(в нашем случае i
) и серия возможных значений (case
). Значение выражения по
очереди сравнивается с выражениями, следующими после ключевого слова case
.
Если они оказываются равны, то выполняется действие, описанное после :
.
Как и условия, обход возможных значений осуществляется сверху вниз, и выбирается
первое значение, которое сошлось с выражением. Переключатель также поддерживает
действие по умолчанию, которое будет выполнено в случае, если не подошло ни одно
из возможных значений (напоминает else
в операторе if
).
Таковы основные операторы управления потоком. Дополнительные операторы будут рассмотрены в следующих главах.
Задачи
Что делает следующий код?
i := 10 if i > 10 { fmt.Println("Big") } else { fmt.Println("Small") }
Напишите программу, которая выводит числа от 1 до 100, которые делятся на 3. (3, 6, 9, …).
Напишите программу, которая выводит числа от 1 до 100. Но для кратных трём нужно вывести «Fizz» вместо числа, для кратных пяти - «Buzz», а для кратных как трём, так и пяти — «FizzBuzz».