Есть ли ключ: v, ok и delete
Map на любой ключ отвечает значением — даже на тот, которого в ней нет. Когда ноль — законное значение, нужно знать, лежит ли пара в map на самом деле.
Ноль или «нет в каталоге»
Ситуация. В map stock — каталог склада. M-120 в каталоге есть, но закончился. T-999 в каталоге нет. Программа отвечает на запросы:
package main
import "fmt"
func main() {
stock := map[string]int{"K-417": 12, "M-120": 0}
for _, sku := range []string{"K-417", "M-120", "T-999"} {
qty := stock[sku]
if qty == 0 {
fmt.Println(sku, "нет в каталоге")
} else {
fmt.Println(sku, "остаток", qty)
}
}
}Что увидите.
stagiaire@lab:~/gocourse/day18/scratch$ go run .
K-417 остаток 12
M-120 нет в каталоге
T-999 нет в каталогеКак это читать. Про M-120 программа говорит неправду. Условие qty == 0 смотрит на значение, а оно у закончившегося товара и у отсутствующего одно — ноль. По значению их не различить.
Для этого у чтения из map есть форма с двумя переменными слева. Сначала предскажите, что она отдаёт.
Попробуйте сейчас: ноль или нет ключа.
Цель: предсказать четыре значения и сдать ответ.
1. Запись
a, okA := stock["M-120"]читает два значения: само значение по ключу и признакtrueилиfalse— есть ли такой ключ в map. Не запуская, прочитайте программу:Код для чтения · разбираем, набирать не нужноpackage main import "fmt" func main() { stock := map[string]int{"K-417": 12, "M-120": 0} a, okA := stock["M-120"] b, okB := stock["T-999"] fmt.Println(a, okA, b, okB) }2. Сдайте четыре значения через пробел, в порядке печати:
▶ Выполните · выделенное замените своимcourse answer day18.q2 ЗНАЧЕНИЕ ЗНАЧЕНИЕ ЗНАЧЕНИЕ ЗНАЧЕНИЕ3. Проверьте запуском:
✎ Наберите в файлscratch/main.gopackage main import "fmt" func main() { stock := map[string]int{"K-417": 12, "M-120": 0} a, okA := stock["M-120"] b, okB := stock["T-999"] fmt.Println(a, okA, b, okB) }▶ Выполнитеcd ~/gocourse/day18/scratch go run .Вывод и разбор — под блоком.
Готово, когда: пункт
q2вcourse check 18зелёный.
v, ok := m[k]
Что увидите.
0 true 0 falseКак это читать.
| Запись | Что значит |
|---|---|
qty, ok := stock[sku] |
qty — значение или нулевое, если ключа нет; ok — true, если ключ есть |
ok |
переменная типа bool; имя — соглашение, так её зовут почти во всём коде на Go |
_, ok := stock[sku] |
значение не нужно, нужен только ответ «есть ли ключ» |
Форма знакома по n, err := strconv.Atoi(s) из дня 12, только отсутствие ключа — не ошибка, и второе значение — простое true или false.
Та же программа с проверкой ok:
package main
import "fmt"
func main() {
stock := map[string]int{"K-417": 12, "M-120": 0}
for _, sku := range []string{"K-417", "M-120", "T-999"} {
qty, ok := stock[sku]
if !ok {
fmt.Println(sku, "нет в каталоге")
} else {
fmt.Println(sku, "остаток", qty)
}
}
}K-417 остаток 12
M-120 остаток 0
T-999 нет в каталогеЕсли ноль и «нет ключа» для задачи значат одно и то же — как у счётчика коробок на следующей странице, — ok не нужен. Если это разные вещи — только ok.
delete: убрать пару
package main
import "fmt"
func main() {
stock := map[string]int{"K-417": 12, "M-120": 0, "P-305": 7}
delete(stock, "M-120")
delete(stock, "T-999")
fmt.Println(len(stock), stock)
_, ok := stock["M-120"]
fmt.Println(ok)
}Что увидите.
2 map[K-417:12 P-305:7]
falseКак это читать. delete(stock, "M-120") убирает пару целиком: длина стала 2, ok на этом ключе — false. Удаление ключа, которого нет, молча ничего не делает. delete, как и len, — встроенная функция, импорт не нужен. Обнулить значение и удалить пару — разные вещи: после stock["M-120"] = 0 ok остаётся true.
Попробуйте сейчас: починить fix2.
Цель: программа в
~/gocourse/day18/fix2отличает артикул с остатком 0 от артикула, которого нет в каталоге.1. Прочитайте комментарий в начале
main.goи запустите на примере:▶ Выполнитеcd ~/gocourse/day18/fix2 cat example.txt go run . < example.txtОдин из артикулов примера в каталоге есть с остатком 0, а программа говорит про него «нет в каталоге».
2. Почините две строки: чтение остатка — двумя значениями, условие — проверка наличия ключа, а не нуля. Каталог и печать не меняйте.
3. Запустите снова и посмотрите правку:
▶ Выполнитеgo run . < example.txt diff ~/.course/orig/day18/fix2/main.go main.go4. Закоммитьте:
▶ Выполнитеcd ~/gocourse/day18 git add . git commit -m "fix2: проверка ok"Готово, когда: артикул с остатком 0 печатается как
остаток 0 шт., отсутствующий —нет в каталоге, правка — не больше двух строк: пунктfix2. Проверка подаст и другие артикулы каталога.
Что может пойти не так
| Что видите | Что это значит | Что делать |
|---|---|---|
declared and not used: ok |
взяли ok и не проверили |
проверить if !ok или читать одной переменной |
| товар с нулевым остатком «нет в каталоге» | условие смотрит на значение qty == 0 |
проверять ok |
после delete пара на месте |
ключ в delete набран с опечаткой, и delete промолчал |
напечатать map до и после, сверить ключ |
fix2: изменено строк больше двух |
переписано больше нужного | cp ~/.course/orig/day18/fix2/main.go main.go и поправить две строки |
Дальше: map как счётчик и как сумма по группе — course next