Я знаю, что могу перебрать карту m
,
for k, v := range m { ... }
и искать ключ, но есть ли более эффективный способ проверки существования ключа на карте?
Я не мог найти ответ в спецификации языка .
Я знаю, что могу перебрать карту m
,
for k, v := range m { ... }
и искать ключ, но есть ли более эффективный способ проверки существования ключа на карте?
Я не мог найти ответ в спецификации языка .
Ответы:
Ответ в одну строку:
if val, ok := dict["foo"]; ok {
//do something here
}
if
операторы в Go могут включать как условие, так и оператор инициализации. В приведенном выше примере используются оба:
инициализирует две переменные - val
получит либо значение «foo» с карты, либо «нулевое значение» (в данном случае пустую строку) и ok
получит значение bool, которое будет установлено в том true
случае, если «foo» действительно присутствовало на карте
оценивает ok
, что будет, true
если "foo" был на карте
Если «foo» действительно присутствует на карте, тело if
оператора будет выполнено и val
будет локальным для этой области.
var val string = ""
останется прежним, val, ok :=
создаст новую локальную переменную с тем же именем, которая видна только в этом блоке.
if key in dict
.
В дополнение к спецификации языка программирования Go вы должны прочитать Effective Go . В разделе о картах , среди прочего, говорится:
Попытка получить значение карты с ключом, которого нет на карте, вернет нулевое значение для типа записей в карте. Например, если карта содержит целые числа, поиск несуществующего ключа вернет 0. Набор может быть реализован как карта со значением типа bool. Установите для записи карты значение true, чтобы поместить значение в набор, а затем протестируйте его с помощью простой индексации.
attended := map[string]bool{ "Ann": true, "Joe": true, ... } if attended[person] { // will be false if person is not in the map fmt.Println(person, "was at the meeting") }
Иногда вам нужно отличить отсутствующую запись от нулевого значения. Есть ли запись для «UTC» или это 0, потому что ее нет на карте вообще? Вы можете различать с помощью формы множественного назначения.
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]
Поиск по списку рассылок и поиск решения, размещенного Питером Фрёлихом 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
условий.
_, ok := dict["baz"]; ok
. _
Часть бросает значение прочь вместо создания временной переменной.
_, 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]
Как отмечено другими ответами, общее решение состоит в том, чтобы использовать индексное выражение в назначении специальной формы:
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
.
Использование этой «техники» имеет и другое преимущество: вы можете компактно проверить наличие нескольких ключей (вы не можете сделать это с помощью специальной формы «запятая нормально»). Подробнее об этом: Проверьте, существует ли ключ на нескольких картах в одном условии
Получение нулевого значения типа значения при индексации с несуществующим ключом также позволяет нам bool
удобно использовать карты со значениями в виде наборов . Например:
set := map[string]bool{
"one": true,
"two": true,
}
fmt.Println("Contains 'one':", set["one"])
if set["two"] {
fmt.Println("'two' is in the set")
}
if !set["three"] {
fmt.Println("'three' is not in the set")
}
Он выводит (попробуйте на Go Playground ):
Contains 'one': true
'two' is in the set
'three' is not in the set
Смотрите связанные: Как я могу создать массив, который содержит уникальные строки?
T
внутри var v, ok T = a[x]
? не ok
должно быть бул?
map[bool]bool
и T
есть bool
, но это также работает, если карта имеет тип map[interface{}]bool
и T
есть interface{}
; Более того, он также работает с пользовательскими типами, имеющими bool
базовый тип, смотрите все на Go Playground . Так как эта форма действительна с заменой нескольких типов T
, поэтому используется общее T
. Тип ok
может быть любым, для которого может быть назначен нетипизированныйbool
.
лучший способ здесь
if _, ok := dict["foo"]; ok {
//do something here
}
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 существует ли какая-нибудь строка? правда не существует? ложный
_, ok = m["somestring"]
должно быть=_, ok := m["somestring"]
Упоминается в разделе «Индексные выражения» .
Индексное выражение на карте a типа map [K] V, используемое в присваивании или инициализации специальной формы
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
дает дополнительное нетипизированное логическое значение. Значение ok равно true, если ключ x присутствует на карте, и false в противном случае.
Для этой цели можно использовать присвоение двух значений. Пожалуйста, проверьте мой пример программы ниже
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")
}
}