День 06 · Условия: if, else, switch · страница 6 из 6

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 — нет.


Попробуйте сейчас: switch по зоне.

Цель: увидеть, какой case срабатывает на разных зонах, дописать свой case и прочитать ошибку повтора.

1. Наберите в scratch/main.go программу с switch по зоне:

✎ Наберите в файл scratch/main.go
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, "не доставляем")
	}
}

Запустите с 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.go
package 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 int

switch 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.txt

2. Сначала таблица примеров: каждая зона, зона вне списка, каждый порог веса — сам порог и на грамм больше. Подумайте, как не печатать строки про тариф, если в зону не возим: хватит одного if после выбора тарифа.

3. Потом код, go run . со всеми примерами, свои числа обратно и проверка формата:

▶ Выполните
go run .
gofmt -l .

Готово, когда: каждый пример из таблицы дал на экране ожидаемое, в первых строках снова ваши числа, gofmt -l . ничего не печатает (пункты проверки delivery, delivery_switch, code_fmt).


Словарик ошибок

В ~/errors.md к концу дня — минимум двенадцать разборов: вчерашние и сегодняшние вместе. Формат прежний: текст ошибки, тире с пробелами вокруг, что это значило у вас. Двоеточие вместо тире проверка не засчитает: оно есть в каждом сообщении компилятора.

Слева от тире — то, что напечатал Go или go vet, своими буквами переписывать не надо; справа — по-русски, что это значило в вашей программе. Строка «сегодня была странная ошибка — разобрался сам» тире содержит, а разбора в ней нет: такую строку проверка не считает.

Сегодня встречались:

Пишите не перевод, а что это значило в вашей программе: «поставил = в условии вместо ==», а не «нельзя использовать присваивание».


Материал дня закончен. Задания — course lab 06, дополнительное чтение — course extra 06