Как проверить, содержит ли карта ключ в Go? - PullRequest
588 голосов
/ 12 января 2010

Я знаю, что могу перебрать карту m,

for k, v := range m { ... }

и ищите ключ, но есть ли более эффективный способ проверки существования ключа на карте?

Я не смог найти ответ в спецификации языка .

Ответы [ 10 ]

1139 голосов
/ 12 января 2010

Ответ в одну строку:

if val, ok := dict["foo"]; ok {
    //do something here
}

Пояснение:

if операторы в Go могут включать как условие, так и оператор инициализации. В приведенном выше примере используются оба:

  • инициализирует две переменные - val получит либо значение "foo" с карты, либо "нулевое значение" (в данном случае пустую строку), а ok получит значение bool установить на true, если на карте действительно присутствовал "foo"

  • оценивает ok, что будет true, если "foo" было на карте

Если "foo" действительно присутствует на карте, тело оператора if будет выполнено и val будет локальным для этой области.

94 голосов
/ 12 января 2010

Редактировать: Следующий ответ предшествует Go 1. Начиная с Go 1, он больше не является точным / действительным.


В дополнение к Спецификации языка программирования Go необходимо прочитать Effective Go . В разделе о картах , среди прочего, говорится:

«Попытка получить значение карты с ключом, которого нет на карте, приведет к сбою программы, но есть способ сделать это безопасно, используя множественное назначение.»

var seconds int
var ok bool
seconds, ok = timeZone[tz]

"Чтобы проверить наличие на карте, не беспокоясь о фактическом значении, вы можете использовать пустой идентификатор, простое подчеркивание (_). Пустой идентификатор может быть назначен или объявлен с любым значением любого типа, со значением безвредно отбрасывается. Для проверки присутствия на карте используйте пустой идентификатор вместо обычной переменной для значения. "

_, present := timeZone[tz]
45 голосов
/ 12 января 2010

Поиск в списке рассылки go-nuts и обнаружение решения, опубликованного Peter Froehlich 15.11.2009.

package main

import "fmt"

func main() {
        dict := map[string]int {"foo" : 1, "bar" : 2}
        value, ok := dict["baz"]
        if ok {
                fmt.Println("value: ", value)
        } else {
                fmt.Println("key not found")
        }
}

Или, более компактно,

if value, ok := dict["baz"]; ok {
    fmt.Println("value: ", value)
} else {
    fmt.Println("key not found")
}

Обратите внимание, что при использовании этой формы оператора if переменные value и ok видны только внутри условий if.

20 голосов
/ 10 ноября 2015

Короткий ответ

_, exists := timeZone[tz]    // Just checks for key existence
val, exists := timeZone[tz]  // Checks for key existence and retrieves the value

Пример

Вот пример на игровой площадке Go .

Более длинный ответ

По разделу Карты Effective Go :

Попытка получить значение карты с ключом, которого нет на карте, вернет нулевое значение для типа записей в карте. Например, если карта содержит целые числа, поиск несуществующего ключа вернет 0.

Иногда вам нужно отличить отсутствующую запись от нулевого значения. Есть ли запись для «UTC» или это пустая строка, потому что ее нет на карте вообще? Вы можете различать с помощью формы множественного назначения.

var seconds int
var ok bool
seconds, ok = timeZone[tz]

По понятным причинам это называется идиома «запятая нормально». В этом примере, если tz присутствует, секунды будут установлены соответствующим образом, и ok будет истинным; если нет, то секунды будут установлены на ноль, и ok будет ложным. Вот функция, которая объединяет это с хорошим сообщением об ошибке:

func offset(tz string) int {
    if seconds, ok := timeZone[tz]; ok {
        return seconds
    }
    log.Println("unknown time zone:", tz)
    return 0
}

Чтобы проверить наличие на карте, не заботясь о фактическом значении, вы можете использовать пустой идентификатор (_) вместо обычной переменной для значения.

_, present := timeZone[tz]
10 голосов
/ 07 апреля 2017

Как отмечалось в других ответах, общее решение заключается в использовании индексного выражения в присваивании специальной формы:

v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]

Это красиво и чисто. Однако у него есть некоторые ограничения: это должно быть присвоение специальной формы. Выражение в правой части должно быть только выражением индекса карты, а список выражений в левой части должен содержать ровно 2 операнда: первый, которому присваивается тип значения, а второй, которому присваивается значение bool. Первое значение результата этого специального выражения индекса формы будет значением, связанным с ключом, а второе значение скажет, существует ли на карте запись с данным ключом (если ключ существует на карте). Список выражений в левой части также может содержать пустой идентификатор , если один из результатов не нужен.

Важно знать, что если индексированное значение карты равно nil или не содержит ключ, индексное выражение оценивается как нулевое значение типа значения карты. Так, например:

m := map[int]string{}
s := m[1] // s will be the empty string ""
var m2 map[int]float64 // m2 is nil!
f := m2[2] // f will be 0.0

fmt.Printf("%q %f", s, f) // Prints: "" 0.000000

Попробуйте на игровой площадке Go .

Так что, если мы знаем, что мы не используем нулевое значение на нашей карте, мы можем воспользоваться этим.

Например, если тип значения string, и мы знаем, что никогда не сохраняем записи на карте, где значением является пустая строка (нулевое значение для типа string), мы также можем проверить, является ли ключ в карте, сравнивая несвойственную форму (результат) выражения индекса с нулевым значением:

m := map[int]string{
    0: "zero",
    1: "one",
}

fmt.Printf("Key 0 exists: %t\nKey 1 exists: %t\nKey 2 exists: %t",
    m[0] != "", m[1] != "", m[2] != "")

Вывод (попробуйте на Go Playground ):

Key 0 exists: true
Key 1 exists: true
Key 2 exists: false

На практике во многих случаях мы не храним значение нулевого значения на карте, поэтому его можно использовать довольно часто. Например, интерфейсы и типы функций имеют нулевое значение nil, которое мы часто не храним в картах. Поэтому можно проверить, есть ли ключ на карте, сравнив его с nil.

Использование этой «техники» имеет и другое преимущество: вы можете компактно проверить наличие нескольких ключей (вы не можете сделать это с помощью специальной формы «запятая нормально»). Подробнее об этом: Проверьте, существует ли ключ на нескольких картах в одном условии

6 голосов
/ 18 октября 2017

лучший способ здесь

if _, ok := dict["foo"]; ok {
    //do something here
}
4 голосов
/ 13 июня 2018

Упоминается под «Индексные выражения» .

Индексное выражение на карте a типа map [K] V, используемое в назначении или инициализация специальной формы

v, ok = a[x] 
v, ok := a[x] 
var v, ok = a[x]

дает дополнительное нетипизированное логическое значение. Значение ok верно, если ключ x присутствует на карте, в противном случае - false.

3 голосов
/ 22 июля 2015
    var empty struct{}
    var ok bool
    var m map[string]struct{}
    m = make(map[string]struct{})
    m["somestring"] = empty


    _, ok = m["somestring"]
    fmt.Println("somestring exists?", ok) 
    _, ok = m["not"]
    fmt.Println("not exists?", ok)

Тогда иди запусти maps.go есть какая-то строка? правда не существует? ложь

1 голос
/ 21 сентября 2018

Для этой цели может использоваться присвоение двух значений. Пожалуйста, проверьте мой пример программы ниже

package main

import (
    "fmt"
)

func main() {
    //creating a map with 3 key-value pairs
    sampleMap := map[string]int{"key1": 100, "key2": 500, "key3": 999}
    //A two value assignment can be used to check existence of a key.
    value, isKeyPresent := sampleMap["key2"]
    //isKeyPresent will be true if key present in sampleMap
    if isKeyPresent {
        //key exist
        fmt.Println("key present, value =  ", value)
    } else {
        //key does not exist
        fmt.Println("key does not exist")
    }
}
0 голосов
/ 02 сентября 2015

Просто используйте

if len(m) == 0 {
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...