Трассировка с map и выбор: срез или map
Последняя страница дня: как map записывается в таблицу трассировки, когда выбирать map, а когда срез, и словарик.
Колонка map в таблице
Ситуация. В программе есть map, и её значение нужно вписать в таблицу трассировки клеткой, как число. Правила 1–29 дней 02, 06, 08, 11, 12, 13, 16 и 17 действуют. К ним три новых. Номера строк — слева:
1 package main
2
3 import "fmt"
4
5 func add(m map[string]int, sku string) {
6 m[sku]++
7 }
8
9 func main() {
10 counts := map[string]int{}
11 counts["T-118"]++
12 counts["A-210"] += 3
13 have := counts["P-305"]
14 add(counts, "T-118")
15 delete(counts, "A-210")
16 fmt.Println(counts, have)
17 }Вызов add — один шаг, шаги внутри функции не расписываем (правило 22).
| шаг | строка | counts | have |
|---|---|---|---|
| 1 | 10 | map[] |
- |
| 2 | 11 | map[T-118:1] |
- |
| 3 | 12 | map[A-210:3 T-118:1] |
- |
| 4 | 13 | map[A-210:3 T-118:1] |
0 |
| 5 | 14 | map[A-210:3 T-118:2] |
0 |
| 6 | 15 | map[T-118:2] |
0 |
| 7 | 16 | map[T-118:2] |
0 |
Правила для map.
- Колонка map записывается так, как её печатает
fmt.Println:map[ключ:значение ключ:значение]— пары через пробел, ключ и значение через двоеточие, ключи по возрастанию, строки без кавычек. Пустая map —map[]; map, которая ещё не объявлена, — прочерк-. На шаге 3 ключA-210добавлен вторым, а стоит первым: порядок в клетке — порядок ключей, а не порядок записи. - Новый ключ появляется в колонке только при записи:
m[k] = …,m[k]++,m[k] += …— даже если прибавили ноль. Чтениеx := m[k]иx, ok := m[k]колонку map не меняет, даже когда ключа нет, — шаг 4.delete(m, k)убирает пару;deleteключа, которого нет, ничего не меняет. - Map, переданная в функцию, — та же самая map: запись внутри функции меняет колонку map вызывающего. Если вызов — один шаг (правило 22), изменение видно уже в строке вызова — шаг 5. Если шаги функции расписаны, колонка вызывающего меняется в той строке функции, где сделана запись. Это исключение из правила 20: у переменных
intиstringвызывающего так не бывает.
Проверить таблицу можно отладочной печатью в копии программы (правило 6). После каждой строки main вставляется печать с номером строки исходной программы, например после строки 10 — fmt.Println("после строки 10:", counts), а после строк с 13-й — fmt.Println("после строки 13:", counts, have):
после строки 10: map[]
после строки 11: map[T-118:1]
после строки 12: map[A-210:3 T-118:1]
после строки 13: map[A-210:3 T-118:1] 0
после строки 14: map[A-210:3 T-118:2] 0
после строки 15: map[T-118:2] 0
map[T-118:2] 0Последняя строка — печать самой программы, шаг 7.
Обход for k, v := range m по самой map по шагам не расписывают: его порядок не определён, и верного ответа у такой таблицы нет. Обход slices.Sorted(maps.Keys(m)) — обычный обход среза (правила дня 16).
Попробуйте сейчас: задание trace.
Цель: все
?в~/gocourse/day18/trace/table.txtзаменены значениями без запуска. Артикулы и числа у каждого свои.1. Откройте программу и таблицу рядом:
▶ Выполнитеcd ~/gocourse/day18/trace cat program.go cat table.txt2. Заполните все
?по правилам 30–32. Артикулы — латиницей, как вprogram.go; колонкаok—trueилиfalse.3. Сверьте клетки отладочной печатью в копии,
program.goне меняйте:▶ Выполнитеcp program.go ~/gocourse/day18/scratch/main.go cd ~/gocourse/day18/scratch go run .В копию после каждой строки
mainдопишитеfmt.Println(stock).4. Закоммитьте:
▶ Выполнитеcd ~/gocourse/day18 git add . git commit -m "trace: таблица с map"Готово, когда: в таблице не осталось
?, пунктtraceзелёный.
Срез или map
| Что нужно | Срез | map |
|---|---|---|
| порядок: строки ввода, очередь заказов | хранит | не хранит |
| найти по артикулу | перебор | сразу, по ключу |
| повторы одного значения | хранит все | один ключ — одна пара |
объявить через var и сразу писать |
append к nil-срезу работает |
запись в nil-map — паника |
Хранить по порядку — срез, считать и группировать — map. Часто вместе, как в задании group: строки ввода — в срезы, итоги — в map, для печати ключи снова становятся отсортированным срезом. Подробная таблица — в course extra 18.
Попробуйте сейчас: история дня.
Цель: убедиться, что работа дня записана.
▶ Выполнитеcd ~/gocourse/day18 git status -s git log --onelineГотово, когда:
git status -sничего не печатает, а вgit log --onelineне меньше четырёх строк — пунктgit. Незакоммиченное —git add .иgit commit -m "…".
Словарик ошибок
Допишите в ~/errors.md сообщения, которые встретили сегодня: текст ошибки, тире, что это значило в вашем коде.
panic: assignment to entry in nil map - объявил map через var и не создал
invalid operation: got != want (map can only be compared to nil) - сравнил две map через !=Нужно не меньше 36 разборов за все дни. Разделитель — тире с пробелами. Кандидаты дня: invalid map key type, duplicate key … in map literal, undefined: maps, does not match iter.Seq[E], declared and not used: ok.
Итог дня
| Что | Как |
|---|---|
| создать | m := map[string]int{}, make(map[string]int), литерал |
| запись, чтение | m[k] = v, x := m[k]; нет ключа — нулевое значение |
| есть ли ключ, удалить | v, ok := m[k], delete(m, k) |
| счётчик и сумма | m[k]++, m[k] += q |
| по возрастанию | for _, k := range slices.Sorted(maps.Keys(m)) |
nil-map |
читать можно, писать — паника |
| в функции и в тесте | та же map; сравнение — maps.Equal |
Завтра — строки изнутри: почему len("Болт") не 4, и чтение файла выгрузки.
Материал дня закончен. Задания — course lab 18, дополнительное чтение — course extra 18