Как в Go проверить, существует ли ключ в `map`?

Ответ

Для проверки наличия ключа в map в Go используется специальная форма присваивания, которая возвращает два значения. Эта идиома называется "comma, ok".

package main

import "fmt"

func main() {
    m := map[string]int{
        "apple":  1,
        "orange": 2,
    }

    // Пытаемся получить значение по ключу "apple"
    val, ok := m["apple"]
    if ok {
        fmt.Printf("Ключ 'apple' существует, значение: %dn", val)
        // Вывод: Ключ 'apple' существует, значение: 1
    }

    // Пытаемся получить значение по несуществующему ключу "banana"
    val, ok = m["banana"]
    if !ok {
        fmt.Printf("Ключ 'banana' не существует. val имеет zero-value: %dn", val)
        // Вывод: Ключ 'banana' не существует. val имеет zero-value: 0
    }
}

Основные моменты:

  1. Два возвращаемых значения: При доступе к map в форме val, ok := m[key], переменная ok будет true, если ключ существует, и false в противном случае.

  2. Проверка только наличия: Если само значение не нужно, можно использовать пустой идентификатор _, чтобы его проигнорировать. Это самый эффективный способ.

    if _, ok := m["orange"]; ok {
        fmt.Println("Ключ 'orange' точно есть в map!")
    }
  3. Почему нельзя просто проверять значение? При обращении к несуществующему ключу map всегда возвращает нулевое значение (zero-value) для типа своих значений. Если у вас map[string]int, то для отсутствующего ключа вернется 0. Но 0 может быть и реальным значением, сохраненным в map. Поэтому проверка if m["key"] != 0 ненадежна.

  4. Производительность Проверка наличия ключа в map — это очень быстрая операция, в среднем занимающая константное время O(1).

Ответ 18+ 🔞

Так, слушай, смотри, блядь. Вот у тебя есть эта штука — map, да? Ну, типа словарь, где ключ к значению привязан. И тебе надо проверить, а есть ли там вообще этот ключ, или ты сейчас будешь в пустоту смотреть, как дурак.

Вот смотри, в Go для этого есть специальная, блядь, приёмка, называется "comma, ok". Выглядит как будто ты два значения из кармана достаёшь, а не одно.

package main

import "fmt"

func main() {
    m := map[string]int{
        "apple":  1,
        "orange": 2,
    }

    // Пытаемся получить значение по ключу "apple"
    val, ok := m["apple"]
    if ok {
        fmt.Printf("Ключ 'apple' существует, значение: %dn", val)
        // Вывод: Ключ 'apple' существует, значение: 1
    }

    // Пытаемся получить значение по несуществующему ключу "banana"
    val, ok = m["banana"]
    if !ok {
        fmt.Printf("Ключ 'banana' не существует. val имеет zero-value: %dn", val)
        // Вывод: Ключ 'banana' не существует. val имеет zero-value: 0
    }
}

Ну и что тут происходит, ёпта?

  1. Два значения, Карл! Когда пишешь val, ok := m[key], эта ok — она как индикатор, блядь. true — ключ есть, всё пиздато. false — ключа нет, и ты сейчас держишь в val полную хуйню, а именно нулевое значение типа.

  2. Если значение не нужно. А зачем тебе это значение, если ты просто проверить хочешь? Сука, используй пустой идентификатор _, как мусорное ведро. Выкинул и забыл. Так даже эффективнее.

    if _, ok := m["orange"]; ok {
        fmt.Println("Ключ 'orange' точно есть в map!")
    }
  3. А почему просто не посмотреть на значение? О, это, блядь, классическая ловушка для распиздяев! Если ключа нет, map тебе всё равно вернёт ноль, пустую строку или nil — в общем, zero-value. И что ты будешь делать, если у тебя в map как раз лежит ноль? Ты подумаешь, что ключа нет, а он есть! Пиздец, обоссаться можно. Поэтому только ok.

  4. А это быстро? Да хуй с ним, с нулём! Главное — быстро? Быстро, блядь! Проверка ключа в map — это операция за константное время, O(1). То есть неважно, там десять элементов или десять миллионов — скорость одна и та же, ёбушки-воробушки.