Перейти к содержимому
Теория · Map · урок 2 из 9

Есть ли ключ

В прошлом уроке мы выяснили: если имени в телефонной книге нет, map отвечает нулевым значением. Обычно это удобно, но иногда мешает. В map с очками игроков значение 0 может быть настоящим результатом. По обычному чтению его не отличить от ключа, которого нет:

GO
package main

import "fmt"

func main() {
    scores := map[string]int{"ann": 0, "bob": 7}
    fmt.Println(scores["ann"], scores["max"]) // 0 0
}

Здесь два разных случая:

  • игрок ann сыграл и набрал ноль очков;
  • игрока max в map нет вовсе.

Оба чтения возвращают 0, потому что отсутствующий ключ читается как нулевое значение. Это всё равно что спросить телефонную книгу о номере, а в ответ услышать «0» и не понять: у человека такой номер или его нет в книге.

Два значения при чтении

Чтение из map может вернуть второе значение типа bool. Оно равно true, если ключ есть, и false, если ключа нет. Такую запись называют идиомой comma ok — по запятой между двумя переменными:

GO
scores := map[string]int{"ann": 0, "bob": 7}
v, ok := scores["ann"]
fmt.Println(v, ok) // 0 true
w, found := scores["max"]
fmt.Println(w, found) // 0 false

Давайте разберём пример по строкам:

  1. v, ok := scores["ann"] читает два значения. Ключ "ann" есть, поэтому ok равно true, хотя v равно 0: важно, есть ли ключ, а не какое у него значение.
  2. fmt.Println(v, ok) печатает 0 true.
  3. w, found := scores["max"] читает отсутствующий ключ. Первое значение нулевое, как при обычном чтении, а второе — false.
  4. fmt.Println(w, found) печатает 0 false.

Имя второй переменной может быть любым: ok — договорённость, а не ключевое слово. Если само значение не нужно, вместо первой переменной пишут _: _, ok := scores["max"].

Этот вопрос часто задают на собеседовании: «Как проверить, есть ли ключ в map?» Ответ — прочитать два значения и посмотреть на второе.

Когда нужна comma ok

Выбор зависит от того, бывает ли нулевое значение настоящим:

  • бывает — ноль очков, пустое имя, false в map[string]bool — тогда нужна comma ok;
  • не бывает — например, цена товара всегда больше нуля — тогда хватает обычного чтения и сравнения с нулём.

Проверка в if

Чаще всего comma ok стоит в инициализации if. Переменные v и ok тогда видны только внутри if и не мешают остальному коду:

GO
scores := map[string]int{"bob": 7}
if v, ok := scores["bob"]; ok {
    fmt.Println("bob:", v) // bob: 7
}
if _, ok := scores["max"]; !ok {
    fmt.Println("no max") // no max
}

Давайте разберём оба if:

  1. Ключ "bob" есть, поэтому первый if печатает его очки: bob: 7.
  2. Ключа "max" нет, ok равно false, и второй if печатает no max.

map как множество

Иногда нулевое значение для отсутствующего ключа как раз помогает. Так устроено множество — набор значений без повторов. Отдельного типа для множества в Go нет, и на собеседовании часто спрашивают, как его сделать. Ответ — map со значениями bool: seen := map[string]bool{}.

Работают с таким множеством так:

  • значение добавляют записью seen[w] = true;
  • проверяют обычным чтением: if seen[w];
  • значение false в такую map никто не пишет, поэтому false при чтении означает одно: этого ключа в множестве нет.

Comma ok здесь не нужна. Так удобно отсеивать повторы: если seen[w] уже true, значение встречалось раньше.

Частая ошибка

Значение сравнивают с нулём, чтобы узнать, есть ли ключ:

GO
scores := map[string]int{"ann": 0}
if scores["ann"] == 0 { // ✗
    fmt.Println("no ann")
}

Программа печатает no ann, хотя ключ "ann" в map есть: его значение 0 совпадает с нулевым значением для отсутствующего ключа. Такая проверка путает игрока с нулём очков и игрока, которого нет. Проверяйте второе значение: if _, ok := scores["ann"]; !ok.

Главное

  • v, ok := m[k] возвращает значение и true, если ключ есть, или нулевое значение и false, если его нет.
  • Comma ok нужна, когда нулевое значение бывает настоящим, как ноль очков.
  • Множество в Go — map[T]bool: добавляют через seen[x] = true, проверяют через if seen[x].

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом