if и else
Сравнение отвечает true или false. Теперь этим ответом нужно распорядиться: одни строки выполнить, только если товара хватает, другие — только если не хватает.
if: выполнить, только если
Ситуация. Программа отгрузки. Если остатка хватает — напечатать, сколько штук отгружаем. Если не хватает — не отгружать ничего.
package main
import "fmt"
func main() {
stock := 40
ordered := 25
if stock >= ordered {
fmt.Println("Отгружаем:", ordered, "шт.")
}
fmt.Println("Проверка заказа закончена")
}Что увидите.
stagiaire@lab:~/gocourse/day06/scratch$ go run .
Отгружаем: 25 шт.
Проверка заказа законченаПоменяйте ordered := 25 на ordered := 55:
stagiaire@lab:~/gocourse/day06/scratch$ go run .
Проверка заказа законченаКак это читать.
| Кусок | Что значит |
|---|---|
if |
«если» |
stock >= ordered |
условие — любое выражение типа bool |
{ в конце строки |
начало блока: строк, которые выполнятся, только если условие true |
} на строке 10 |
конец блока; дальше программа идёт как обычно |
Порядок выполнения. Строки 6 и 7 — как всегда. На строке 8 исполнитель вычисляет условие. Если true, он заходит в блок, выполняет строку 9 и после } переходит к строке 11. Если false, он перескакивает весь блок и сразу выполняет строку 11. Строка 11 выполняется в обоих случаях: она стоит после блока.
stock >= ordered ?
/ \
true false
| |
Println("Отгружаем:" …) |
\ /
Println("Проверка заказа закончена")Правила записи — их проверяет компилятор:
{— на той же строке, чтоif, как уfunc main() {. Причина та же: в конце строки компилятор ставит невидимую точку с запятой (день 01, extra), иifбез блока становится ошибкой.- Скобки вокруг условия не нужны.
if (stock >= ordered) {соберётся, ноgofmtи Ctrl+S уберут скобки: в Go так не пишут. - Фигурные скобки обязательны, даже если в блоке одна строка.
Попробуйте сейчас: if на трёх заказах.
Цель: увидеть, когда блок
ifвыполняется, а когда пропускается, и предсказать случай «ровно столько, сколько на складе».1. Наберите в
scratch/main.goпрограмму сif:✎ Наберите в файлscratch/main.gopackage main import "fmt" func main() { stock := 40 ordered := 25 if stock >= ordered { fmt.Println("Отгружаем:", ordered, "шт.") } fmt.Println("Проверка заказа закончена") }Запустите, потом поменяйте
ordered := 25наordered := 55и запустите снова:▶ Выполнитеcd ~/gocourse/day06/scratch go run .2. Третий запуск — с
ordered := 40, ровно столько, сколько на складе. Предскажите вывод до запуска:>=включает равенство или нет? Потомgo run ..Готово, когда: при 25 и 55 вывод совпал с «Что увидите» выше, а при 40 — с вашим предсказанием.
else: иначе
Ситуация. Если товара не хватает, программа должна сказать, сколько штук не хватает.
package main
import "fmt"
func main() {
stock := 40
ordered := 55
if stock >= ordered {
fmt.Println("Отгружаем:", ordered, "шт.")
} else {
fmt.Println("Не хватает:", ordered-stock, "шт.")
}
fmt.Println("Проверка заказа закончена")
}stagiaire@lab:~/gocourse/day06/scratch$ go run .
Не хватает: 15 шт.
Проверка заказа законченаКак это читать. else — «иначе». Из двух блоков выполняется ровно один: при true — первый (строка 9), при false — второй (строка 11). Не бывает, чтобы выполнились оба или ни одного.
Во втором блоке ordered-stock не может стать отрицательным: сюда программа попадает, только когда stock >= ordered оказалось false, то есть заказ больше остатка. Каждая ветка «знает», при каком условии в неё пришли, — это пригодится на следующей странице.
} else { пишется одной строкой: закрывающая скобка первого блока, слово else, открывающая скобка второго. else на отдельной строке — ошибка компиляции, она в таблице ниже.
Переменная внутри блока
Ситуация. Статус заказа выбирается в ветках, а печатается после них.
stock := 40
ordered := 55
if stock >= ordered {
status := "отгружаем"
} else {
status := "ждём поставку"
}
fmt.Println("Статус:", status)stagiaire@lab:~/gocourse/day06/scratch$ go run .
# day06/scratch
./main.go:9:3: declared and not used: status
./main.go:11:3: declared and not used: status
./main.go:13:31: undefined: statusКак это читать. Переменная, объявленная внутри { }, существует только до своей }. Здесь объявлены две разные переменные status, каждая в своём блоке, и ни одна там не использована — отсюда два declared and not used. На строке 13 обе уже исчезли — undefined. Три сообщения, а причина одна: объявление стоит не на том уровне.
Часть программы, где имя видно, называется областью видимости. Подробнее о ней — в блоке 3, когда появятся свои функции.
Правильно — объявить переменную до if, а в ветках только присваивать, знаком =:
stock := 40
ordered := 55
var status string
if stock >= ordered {
status = "отгружаем"
} else {
status = "ждём поставку"
}
fmt.Println("Статус:", status)Статус: ждём поставкуОпаснее всего := в ветке, когда снаружи уже есть переменная с тем же именем. Программа соберётся, но := создаст внутри блока новую переменную, а наружная останется прежней:
price := 1000
if price > 500 {
price := price - 100
fmt.Println(price)
}
fmt.Println(price)900
1000Попробуйте сейчас: переменная внутри блока.
Цель: прочитать три сообщения об объявлении в ветке и починить программу переносом объявления.
1. Наберите в
scratch/main.goпрограмму соstatus :=в ветках — целиком, чтобы номера строк в сообщениях совпали с вашими:✎ Наберите в файлscratch/main.gopackage main import "fmt" func main() { stock := 40 ordered := 55 if stock >= ordered { status := "отгружаем" } else { status := "ждём поставку" } fmt.Println("Статус:", status) }Запустите и прочитайте все три сообщения:
▶ Выполнитеcd ~/gocourse/day06/scratch go run .2. Почините её переносом объявления до
ifи запуститеgo run .снова.3. Поставьте
ordered := 30и предскажите статус до запуска.Готово, когда: первый запуск дал два
declared and not used: statusиundefined: status; после починки программа напечаталаСтатус: ждём поставку; приordered := 30статус совпал с предсказанием.
Что может пойти не так
Число вместо условия. В некоторых языках число в условии значит «не ноль». В Go условие — только bool:
stock := 40
if stock {
fmt.Println("Товар есть")
}# day06/scratch
./main.go:7:5: non-boolean condition in if statement= вместо ==. В условии нужно сравнение, а написано присваивание:
stock := 0
if stock = 0 {
fmt.Println("Товара нет")
}# day06/scratch
./main.go:7:11: syntax error: cannot use assignment stock = 0 as valueelse на новой строке:
stock := 40
ordered := 55
if stock >= ordered {
fmt.Println("Отгружаем")
}
else {
fmt.Println("Не хватает")
}# day06/scratch
./main.go:11:2: syntax error: unexpected keyword else, expected }Компилятор поставил точку с запятой после } на строке 10 и счёл if законченным. Строка, начинающаяся с else, ему непонятна.
| Что видите | Что это значит | Что делать |
|---|---|---|
non-boolean condition in if statement |
в условии не bool, а число или строка |
написать сравнение: stock > 0 |
syntax error: cannot use assignment stock = 0 as value |
в условии = вместо == |
== |
syntax error: missing condition in if statement |
после if условия нет вовсе: if { |
написать условие: if stock > 0 { |
syntax error: unexpected keyword else, expected } |
else перенесён на новую строку |
} else { одной строкой |
syntax error: unexpected newline, expected { after if clause |
{ перенесена на следующую строку или забыта |
{ в конце строки с if |
syntax error: else must be followed by if or statement block и следом non-declaration statement outside function body |
после else написано условие: } else days > 3 { |
у else условия не бывает; нужно условие — else if, следующая страница |
declared and not used: left на строке внутри блока |
переменную объявили в ветке и не использовали в ней | использовать в блоке или объявить до if |
undefined: status после } |
переменная объявлена внутри блока и за ним не существует | объявить до if, в ветках — = |
собралось, но после if у переменной старое значение |
в ветке := создал новую переменную |
в ветке = |
Попробуйте сейчас: починка fix2.
Цель:
fix2собирается и при нулевом и ненулевом остатке печатает то, что обещано в комментарии в начале файла.1. Программа
fix2не собирается. Что она должна делать — в комментарии в начале файла. Запустите:▶ Выполнитеcd ~/gocourse/day06/fix2 go run .2. Найдите строку из сообщения, почините её и запустите
go run .снова. Хватает одной строки; проверка принимает не больше двух — тот же лимит записан вcourse lab 06.3. Теперь посмотрите вторую ветку: поставьте
stock := 5, запустите и верните обратноstock := 0. Это опыт, а не часть починки: строкаstock := 0должна остаться такой, какой была, — проверка сама подставляет в неё разные остатки. Возвращённая строка в размер правки не попадёт, забытаяstock := 5— попадёт.4. Посмотрите, что изменили, сравнив с оригиналом:
▶ Выполнитеdiff ~/.course/orig/day06/fix2/main.go main.goСтроки с
<— как было, с>— как стало. Новые сообщения запишите в~/errors.md, через тире.Готово, когда: при
stock := 0иstock := 5программа собирается и печатает обещанное в комментарии, в файле сноваstock := 0, аdiffпоказывает только вашу правку (пункты проверкиfix2иt_diff).
Дальше: цепочка else if и почему порядок проверок решает всё — course next