Я знаю, що можу повторити карту 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 , слід прочитати « Ефективний перехід» . У розділі про карти , серед іншого, вони говорять:
Спроба отримати значення карти за допомогою ключа, якого немає на карті, поверне нульове значення для типу записів на карті. Наприклад, якщо карта містить цілі числа, пошук неіснуючого ключа поверне 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, секунди будуть встановлені відповідним чином, і нормально буде вірно; якщо ні, секунди будуть встановлені на нуль, а нормально - помилково. Ось функція, яка поєднує його з приємним звітом про помилку:
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
Щоб перевірити наявність на карті, не турбуючись про фактичне значення, ви можете використовувати порожній ідентифікатор (_) замість звичайної змінної для значення.
_, present := timeZone[tz]
Шукали у списку електронних листів з горіхами та знайшли рішення, розміщене 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
умов.
_, 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 Go .
Згідно з розділом " Ефективний перехід" на Картах :
Спроба отримати значення карти за допомогою ключа, якого немає на карті, поверне нульове значення для типу записів на карті. Наприклад, якщо карта містить цілі числа, пошук неіснуючого ключа поверне 0.
Іноді потрібно відрізняти пропущений запис від нульового значення. Чи є запис для "UTC" чи це порожній рядок, оскільки його взагалі немає на карті? Ви можете розрізнити форму множинного призначення.
var seconds int var ok bool seconds, ok = timeZone[tz]
З очевидних причин це називається ідіомою «кома в порядку». У цьому прикладі, якщо присутній tz, секунди будуть встановлені відповідним чином, і нормально буде вірно; якщо ні, секунди будуть встановлені на нуль, а нормально - помилково. Ось функція, яка поєднує його з приємним звітом про помилку:
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 ):
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 ):
Contains 'one': true
'two' is in the set
'three' is not in the set
Див. Пов'язане: Як я можу створити масив, який містить унікальні рядки?
T
в var v, ok T = a[x]
? не ok
повинен бути bool?
map[bool]bool
та T
є bool
, але вона також працює, якщо карта має тип map[interface{}]bool
і T
є interface{}
; крім того, він також працює з типовими типами, що мають bool
базовий тип, дивіться все на майданчику Go . Оскільки ця форма є дійсною для декількох типів, замінених на них 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 типу типу [K] V, який використовується в призначенні або ініціалізації спеціальної форми
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
дає додаткове нетипізоване булеве значення. Значення ОК вірно, якщо ключ x присутній на карті, а помилкове - в іншому випадку.
Для цього можна використовувати двозначне призначення. Будь ласка, перевірте мою зразок програми нижче
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")
}
}