switch
Цепочка else if справляется с любым выбором, но когда одну переменную сравнивают с длинным списком значений, читать её тяжело:
zone == 1, zone == 2 || zone == 3, zone == 4… Для этого есть switch.
switch по значению
Ситуация. Тариф доставки по зоне: зона 1 — город, зоны 2 и 3 — область, зона 4 — дальние районы, в остальные не возим.
package main
import "fmt"
func main() {
zone := 3
switch zone {
case 1:
fmt.Println("Город: 250 руб.")
case 2, 3:
fmt.Println("Область: 400 руб.")
case 4:
fmt.Println("Дальние районы: 700 руб.")
default:
fmt.Println("В зону", zone, "не доставляем")
}
}Что увидите.
stagiaire@lab:~/gocourse/day06/scratch$ go run .
Область: 400 руб.Как это читать.
| Кусок | Что значит |
|---|---|
switch zone { |
взять значение zone и сравнивать его с каждым case сверху вниз |
case 1: |
если zone == 1 — выполнить строки до следующего case |
case 2, 3: |
несколько значений через запятую: zone == 2 или zone == 3 |
default: |
ни один case не подошёл — как else в цепочке |
Выполняется первый подошедший case, после его строк switch заканчивается. break в конце ветки не нужен: в C, Java и JavaScript без него выполнение переходит в следующий case, в Go — нет.
defaultможно не писать — тогда при неподходящем значении не выполнится ничего.- Значения в
case— того же типа, что выражение послеswitch. Для строки:switch status { case "new": … case "paid", "packed": … }. case 2:без строк под ним значит «при 2 ничего не делать», а не «то же, что в следующемcase». Для общего действия значения пишут через запятую.- Слово
fallthroughпоследней строкой ветки заставляет выполнить ещё и следующийcase. В курсе его не используем: такой код трудно читать.
Попробуйте сейчас: switch по зоне.
Цель: увидеть, какой
caseсрабатывает на разных зонах, дописать свойcaseи прочитать ошибку повтора.1. Наберите в
scratch/main.goпрограмму сswitchпо зоне:✎ Наберите в файлscratch/main.gopackage main import "fmt" func main() { zone := 3 switch zone { case 1: fmt.Println("Город: 250 руб.") case 2, 3: fmt.Println("Область: 400 руб.") case 4: fmt.Println("Дальние районы: 700 руб.") default: fmt.Println("В зону", zone, "не доставляем") } }Запустите с
zone, равным 1, 3, 4 и 9:▶ Выполнитеcd ~/gocourse/day06/scratch go run .2. Допишите
case 5:с «Соседний регион: 900 руб.».3. Попробуйте написать
case 2, 1:— прочитайте, что скажет компилятор.Готово, когда: на 1, 3, 4 и 9 напечатана строка своего
caseилиdefault; приzone := 5— «Соседний регион: 900 руб.»; наcase 2, 1:компилятор ответилduplicate case 1 … in expression switch.
switch без выражения
Ситуация. Доплата за вес: до 1000 г — без доплаты, до 5000 г — 150 руб., тяжелее — 400 руб. Здесь не значения, а диапазоны.
weight := 3700
switch {
case weight <= 1000:
fmt.Println("Лёгкий: без доплаты")
case weight <= 5000:
fmt.Println("Средний: доплата 150 руб.")
default:
fmt.Println("Тяжёлый: доплата 400 руб.")
}Средний: доплата 150 руб.Как это читать. После switch ничего не написано, а в каждом case — условие типа bool. Выполняется первый case, чьё условие true. Это та же цепочка if … else if … else, записанная столбиком, и правило порядка с третьей страницы действует и здесь:
weight := 700
switch {
case weight <= 5000:
fmt.Println("Средний")
case weight <= 1000:
fmt.Println("Лёгкий")
}Средний700 г меньше 5000 — первый case подошёл, до «Лёгкого» очередь не дошла. Для <= пороги идут от меньшего к большему.
Что выбрать.
| Задача | Запись |
|---|---|
| одна переменная и список отдельных значений: зона, статус, код | switch переменная { case …: } |
| диапазоны и пороги одной величины | switch { case …: } или цепочка else if — как читается легче |
| два варианта или условия про разные переменные | if / else |
Попробуйте сейчас: что выведет программа?
Цель: пройти два
switchв голове и сдать ответday06.q4.1. Блок ниже только для чтения — пройдите его в голове:
Код для чтения · разбираем, набирать не нужноzone := 3 weight := 5000 price := 0 switch zone { case 1: price = 250 case 2, 3: price = 400 default: price = 900 } switch { case weight > 5000: price += 300 case weight > 1000: price += 150 case weight >= 5000: price += 500 } fmt.Println(price)Оба
switchработают по очереди с одной и той же переменнойprice.2. Сдайте предсказание — до запуска:
▶ Выполните · выделенное замените своимcourse answer day06.q4 ЧИСЛОВместо
ЧИСЛО— число, которое напечатает программа.3. Теперь проверьте себя запуском. Наберите в
scratch/main.goту же программу целиком:✎ Наберите в файлscratch/main.gopackage main import "fmt" func main() { zone := 3 weight := 5000 price := 0 switch zone { case 1: price = 250 case 2, 3: price = 400 default: price = 900 } switch { case weight > 5000: price += 300 case weight > 1000: price += 150 case weight >= 5000: price += 500 } fmt.Println(price) }▶ Выполнитеcd ~/gocourse/day06/scratch go run .Готово, когда: ответ сдан до запуска, и запуск его подтвердил; в
course check 06пункт «Что выведет: switch по зоне и switch без выражения» (q4) отмечен ✔.
Что может пойти не так
Одно значение в двух case:
zone := 3
switch zone {
case 1:
fmt.Println("Город")
case 2, 1:
fmt.Println("Область")
}stagiaire@lab:~/gocourse/day06/scratch$ go run .
# day06/scratch
./main.go:10:10: duplicate case 1 (constant of type int) in expression switch
./main.go:8:7: previous caseВторая строка с отступом — не отдельная ошибка, а подсказка: где это значение встретилось раньше.
Условие в switch с выражением:
weight := 3700
switch weight {
case weight <= 1000:
fmt.Println("Лёгкий")
}# day06/scratch
./main.go:8:7: cannot convert weight <= 1000 (untyped bool value) to type intswitch weight сравнивает weight со значением из case, а там bool. Для диапазонов — switch без выражения.
| Что видите | Что это значит | Что делать |
|---|---|---|
duplicate case 1 (constant of type int) in expression switch и previous case |
одно значение в двух case |
оставить в одном |
cannot convert weight <= 1000 (untyped bool value) to type int |
условие в case при switch weight |
switch { без выражения |
cannot convert "1" (untyped string constant) to type int |
в case строка, а zone — число |
case 1: без кавычек |
syntax error: unexpected newline, expected : |
после case 2 нет двоеточия |
case 2: |
при значении из пустого case 2: ничего не напечаталось |
пустой case не переходит в следующий |
значения через запятую: case 2, 3: |
в switch { сработал не тот case |
широкое условие выше узкого | тот же порядок, что в else if |
| переменная осталась начальной | ни один case не подошёл, default нет |
добавить default |
Попробуйте сейчас: задание delivery.
Цель:
delivery/main.goсчитает стоимость доставки по зоне и весу: тариф —switch zone, доплата —switchбез выражения. Это часть задания, а не пожелание: решение цепочкойelse ifпроверка не засчитает, даже если вывод верный. Иswitchрядом с расчётом «для вида» тоже: проверка убирает в копии программы тела его ветвей — у работающегоswitchвывод от этого обязан измениться.1. Прочитайте условие:
▶ Выполнитеcd ~/gocourse/day06/delivery cat TASK.txt2. Сначала таблица примеров: каждая зона, зона вне списка, каждый порог веса — сам порог и на грамм больше. Подумайте, как не печатать строки про тариф, если в зону не возим: хватит одного
ifпосле выбора тарифа.3. Потом код,
go run .со всеми примерами, свои числа обратно и проверка формата:▶ Выполнитеgo run . gofmt -l .Готово, когда: каждый пример из таблицы дал на экране ожидаемое, в первых строках снова ваши числа,
gofmt -l .ничего не печатает (пункты проверкиdelivery,delivery_switch,code_fmt).
Словарик ошибок
В ~/errors.md к концу дня — минимум двенадцать разборов: вчерашние и сегодняшние вместе. Формат прежний: текст ошибки, тире с пробелами вокруг, что это значило у вас. Двоеточие вместо тире проверка не засчитает: оно есть в каждом сообщении компилятора.
Слева от тире — то, что напечатал Go или go vet, своими буквами переписывать не надо; справа — по-русски, что это значило в вашей программе. Строка «сегодня была странная ошибка — разобрался сам» тире содержит, а разбора в ней нет: такую строку проверка не считает.
Сегодня встречались:
non-boolean condition in if statementsyntax error: cannot use assignment stock = 0 as valuesyntax error: missing condition in if statementsyntax error: unexpected keyword else, expected }syntax error: unexpected newline, expected { after if clauseinvalid operation: … (mismatched types float64 and int)invalid operation: … (mismatched types string and untyped int)declared and not usedв ветке иundefinedпосле}panic: runtime error: integer divide by zeroв условии с&&suspect orотgo vetduplicate case … in expression switchcannot convert … (untyped bool value) to type int
Пишите не перевод, а что это значило в вашей программе: «поставил = в условии вместо ==», а не «нельзя использовать присваивание».
Материал дня закончен. Задания — course lab 06, дополнительное чтение — course extra 06