Wiem, że mogę iterować po mapie m
,
for k, v := range m { ... }
i poszukaj klucza, ale czy istnieje bardziej skuteczny sposób testowania istnienia klucza na mapie?
Nie mogłem znaleźć odpowiedzi w specyfikacji języka .
Wiem, że mogę iterować po mapie m
,
for k, v := range m { ... }
i poszukaj klucza, ale czy istnieje bardziej skuteczny sposób testowania istnienia klucza na mapie?
Nie mogłem znaleźć odpowiedzi w specyfikacji języka .
Odpowiedzi:
Odpowiedź w jednym wierszu:
if val, ok := dict["foo"]; ok {
//do something here
}
if
instrukcje w Go mogą zawierać zarówno warunek, jak i instrukcję inicjalizacji. W powyższym przykładzie wykorzystano oba:
inicjuje dwie zmienne - val
otrzyma wartość „foo” z mapy lub „wartość zerową” (w tym przypadku pusty ciąg znaków) i ok
otrzyma wartość bool, która zostanie ustawiona, true
jeśli „foo” faktycznie byłoby obecne na mapie
ocenia ok
, co będzie, true
jeśli „foo” było na mapie
Jeśli „foo” rzeczywiście jest obecne na mapie, treść if
instrukcji zostanie wykonana i val
będzie lokalna w tym zakresie.
var val string = ""
pozostanie taki sam, val, ok :=
tworzy nową zmienną lokalną o tej samej nazwie, która jest widoczna tylko w tym bloku.
if key in dict
.
Oprócz specyfikacji języka programowania The Go , powinieneś przeczytać Effective Go . W części dotyczącej map mówią między innymi:
Próba pobrania wartości mapy za pomocą klucza, którego nie ma na mapie, zwróci wartość zerową dla typu pozycji na mapie. Na przykład, jeśli mapa zawiera liczby całkowite, wyszukiwanie nieistniejącego klucza zwróci 0. Zestaw można zaimplementować jako mapę o wartości typu bool. Ustaw wpis mapy na wartość true, aby wstawić wartość do zestawu, a następnie przetestuj ją przez proste indeksowanie.
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") }
Czasami musisz odróżnić brakujący wpis od wartości zerowej. Czy istnieje wpis „UTC”, czy jest to 0, ponieważ w ogóle go nie ma na mapie? Możesz dyskryminować formę wielokrotnego przydziału.
var seconds int var ok bool seconds, ok = timeZone[tz]
Z oczywistych powodów nazywa się to idiomem „przecinek”. W tym przykładzie, jeśli występuje tz, sekundy zostaną odpowiednio ustawione i ok będzie prawdą; jeśli nie, sekundy zostaną ustawione na zero, a ok będzie fałszywe. Oto funkcja, która łączy go z ładnym raportem błędu:
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
Aby przetestować obecność na mapie bez obawy o rzeczywistą wartość, możesz użyć pustego identyfikatora (_) zamiast zwykłej zmiennej dla wartości.
_, present := timeZone[tz]
Poszukałem na liście e-maili go-nuts i znalazłem rozwiązanie opublikowane przez Peter Froehlich w dniu 11/15/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")
}
}
Lub, bardziej kompaktowo,
if value, ok := dict["baz"]; ok {
fmt.Println("value: ", value)
} else {
fmt.Println("key not found")
}
Uwaga: przy użyciu tej formy if
instrukcji zmienne value
i ok
są widoczne tylko wewnątrz if
warunków.
_, ok := dict["baz"]; ok
. _
Część rzuca wartość dala zamiast tworzenia zmiennej tymczasowej.
_, exists := timeZone[tz] // Just checks for key existence
val, exists := timeZone[tz] // Checks for key existence and retrieves the value
Oto przykład na Go Playground .
Według sekcji Effective Go w sekcji Mapy :
Próba pobrania wartości mapy za pomocą klucza, którego nie ma na mapie, zwróci wartość zerową dla typu pozycji na mapie. Na przykład, jeśli mapa zawiera liczby całkowite, wyszukiwanie nieistniejącego klucza zwróci 0.
Czasami musisz odróżnić brakujący wpis od wartości zerowej. Czy istnieje wpis „UTC”, czy jest to pusty ciąg, ponieważ w ogóle go nie ma na mapie? Możesz dyskryminować formę wielokrotnego przydziału.
var seconds int var ok bool seconds, ok = timeZone[tz]
Z oczywistych powodów nazywa się to idiomem „przecinek”. W tym przykładzie, jeśli występuje tz, sekundy zostaną odpowiednio ustawione i ok będzie prawdą; jeśli nie, sekundy zostaną ustawione na zero, a ok będzie fałszywe. Oto funkcja, która łączy go z ładnym raportem błędu:
func offset(tz string) int { if seconds, ok := timeZone[tz]; ok { return seconds } log.Println("unknown time zone:", tz) return 0 }
Aby przetestować obecność na mapie bez obawy o rzeczywistą wartość, możesz użyć pustego identyfikatora (_) zamiast zwykłej zmiennej dla wartości.
_, present := timeZone[tz]
Jak zauważono w innych odpowiedziach, ogólnym rozwiązaniem jest użycie wyrażenia indeksu w przypisaniu specjalnej formy:
v, ok = a[x]
v, ok := a[x]
var v, ok = a[x]
var v, ok T = a[x]
To jest miłe i czyste. Ma jednak pewne ograniczenia: musi to być specjalne zadanie. Wyrażenie po prawej stronie musi być tylko wyrażeniem indeksu mapy, a lista wyrażeń po lewej stronie musi zawierać dokładnie 2 operandy, po pierwsze, do którego można przypisać typ wartości, a po drugie, do którego bool
można przypisać wartość. Pierwsza wartość wyniku tego specjalnego formularza będzie wartością powiązaną z kluczem, a druga wartość pokaże, czy rzeczywiście istnieje wpis na mapie z danym kluczem (jeśli klucz istnieje na mapie). Lista wyrażeń po lewej stronie może również zawierać pusty identyfikator, jeśli jeden z wyników nie jest potrzebny.
Ważne jest, aby wiedzieć, że jeśli indeksowana wartość mapy zawiera nil
lub nie zawiera klucza, wyrażenie indeksu ocenia na wartość zerową typu wartości mapy. Na przykład:
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
Wypróbuj na placu zabaw Go .
Więc jeśli wiemy, że nie używamy wartości zerowej na naszej mapie, możemy to wykorzystać.
Na przykład, jeśli typem wartości jest string
i wiemy, że nigdy nie przechowujemy pozycji na mapie, gdzie wartość jest pustym ciągiem (zerowa wartość dla string
typu), możemy również sprawdzić, czy klucz znajduje się na mapie, porównując niespecjalne forma (indeksu) wyrażenia indeksu do wartości zerowej:
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] != "")
Wyjście (wypróbuj na Go Playground ):
Key 0 exists: true
Key 1 exists: true
Key 2 exists: false
W praktyce istnieje wiele przypadków, w których nie przechowujemy wartości zerowej na mapie, więc można jej używać dość często. Na przykład interfejsy i typy funkcji mają zerową wartość nil
, której często nie przechowujemy w mapach. Dlatego sprawdzenie, czy klucz znajduje się na mapie, można osiągnąć, porównując go nil
.
Korzystanie z tej „techniki” ma jeszcze jedną zaletę: możesz sprawdzić istnienie wielu kluczy w kompaktowy sposób (nie możesz tego zrobić za pomocą specjalnego formularza „przecinek”). Więcej na ten temat: Sprawdź, czy klucz istnieje na wielu mapach w jednym stanie
Uzyskanie wartości zerowej typu wartości podczas indeksowania z nieistniejącym kluczem pozwala nam również bool
wygodnie korzystać z map z wartościami jako zestawami . Na przykład:
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")
}
Wyprowadza (wypróbuj na Go Playground ):
Contains 'one': true
'two' is in the set
'three' is not in the set
Zobacz powiązane: Jak mogę utworzyć tablicę zawierającą unikalne ciągi?
T
w var v, ok T = a[x]
środku nie ok
musi być bool?
map[bool]bool
i T
jest bool
, ale działa również, jeśli mapa jest typu map[interface{}]bool
i T
jest interface{}
; ponadto działa również z niestandardowymi typami posiadającymi bool
jako typ podstawowy, zobacz wszystkie na Go Playground . Ponieważ ten formularz jest prawidłowy, a wiele typów jest zastępowanych T
, dlatego T
używany jest ogólny . Typem ok
może być dowolny obiekt, do którego można przypisać typ bez typubool
.
lepszy sposób tutaj
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)
Następnie uruchom mapy. Może coś istnieje? prawda nie istnieje? fałszywe
_, ok = m["somestring"]
powinno być=_, ok := m["somestring"]
Jest wspomniany w „Wyrażeniach indeksu” .
Wyrażenie indeksu na mapie typu mapy [K] V używane w przypisaniu lub inicjacji formularza specjalnego
v, ok = a[x] v, ok := a[x] var v, ok = a[x]
daje dodatkową nietypową wartość boolowską. Wartość ok jest prawdą, jeśli klucz x jest obecny na mapie, a fałsz w przeciwnym razie.
W tym celu można zastosować przypisanie dwóch wartości. Sprawdź mój przykładowy program poniżej
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")
}
}