Szukaj…
Wprowadzenie
Mapy to typy danych używane do przechowywania nieuporządkowanych par klucz-wartość, dzięki czemu wyszukiwanie wartości powiązanej z danym kluczem jest bardzo wydajne. Klucze są unikalne. Podstawowa struktura danych rośnie w miarę potrzeb, aby pomieścić nowe elementy, więc programista nie musi martwić się o zarządzanie pamięcią. Są one podobne do tego, co inne języki nazywają tablicami mieszającymi, słownikami lub tablicami asocjacyjnymi.
Składnia
- var mapName map [KeyType] ValueType // deklaruj mapę
- var mapName = map [KeyType] ValueType {} // deklaruj i przypisuj pustą mapę
- var mapName = map [KeyType] ValueType {klucz1: val1, klucz2: val2} // deklaruj i przypisuj mapę
- mapName: = make (map [KeyType] ValueType) // deklaruj i inicjuj domyślną mapę rozmiarów
- mapName: = make (map [KeyType] ValueType, length) // zadeklaruj i zainicjuj długość rozmiar map
- mapName: = map [KeyType] ValueType {} // automatyczne deklarowanie i przypisywanie pustej mapy za pomocą: =
- mapName: = map [KeyType] ValueType {klucz1: wartość1, klucz2: wartość2} // automatyczne deklarowanie i przypisywanie mapy za pomocą: =
- value: = mapName [klucz] // Uzyskaj wartość według klucza
- wartość, hasKey: = mapName [klucz] // Uzyskaj wartość według klucza, „hasKey” ma wartość „prawda”, jeśli klucz istnieje na mapie
- mapName [klucz] = wartość // Ustaw wartość według klucza
Uwagi
Go zapewnia wbudowany typ map
który implementuje tablicę skrótów . Mapy to wbudowany asocjacyjny typ danych Go (zwany także skrótami lub słownikami w innych językach).
Deklaracja i inicjalizacja mapy
Definiujesz mapę za pomocą słowa kluczowego map
, a następnie rodzajów jej kluczy i ich wartości:
// Keys are ints, values are ints.
var m1 map[int]int // initialized to nil
// Keys are strings, values are ints.
var m2 map[string]int // initialized to nil
Mapy są typami referencyjnymi, a raz zdefiniowane mają zerową wartość nil
. Zapis do zera mapy spowoduje panikę, a odczyty zawsze zwrócą wartość zerową.
Aby zainicjować mapę, użyj funkcji make
:
m := make(map[string]int)
Dzięki dwuparametrowej formie make
możliwe jest określenie początkowej pojemności wejścia dla mapy, zastępując pojemność domyślną:
m := make(map[string]int, 30)
Alternatywnie możesz zadeklarować mapę, inicjując ją do wartości zerowej, a następnie przypisać jej dosłowną wartość później, co pomaga, jeśli przekształcisz strukturę w json, tworząc w ten sposób pustą mapę po powrocie.
m := make(map[string]int, 0)
Możesz także utworzyć mapę i ustawić jej wartość początkową za pomocą nawiasów klamrowych ( {}
).
var m map[string]int = map[string]int{"Foo": 20, "Bar": 30}
fmt.Println(m["Foo"]) // outputs 20
Wszystkie poniższe instrukcje powodują powiązanie zmiennej z tą samą wartością.
// Declare, initializing to zero value, then assign a literal value.
var m map[string]int
m = map[string]int{}
// Declare and initialize via literal value.
var m = map[string]int{}
// Declare via short variable declaration and initialize with a literal value.
m := map[string]int{}
Możemy również użyć literału mapy, aby utworzyć nową mapę z kilkoma początkowymi parami klucz / wartość .
Kluczem może być dowolny porównywalny typ; w szczególności wyklucza to funkcje, mapy i wycinki . Typem wartości może być dowolny typ, w tym typy niestandardowe lub interface{}
.
type Person struct {
FirstName string
LastName string
}
// Declare via short variable declaration and initialize with make.
m := make(map[string]Person)
// Declare, initializing to zero value, then assign a literal value.
var m map[string]Person
m = map[string]Person{}
// Declare and initialize via literal value.
var m = map[string]Person{}
// Declare via short variable declaration and initialize with a literal value.
m := map[string]Person{}
Tworzenie mapy
Można zadeklarować i zainicjować mapę w pojedynczej instrukcji, używając literału złożonego .
Korzystanie z deklaracji zmiennej typu krótkiego typu automatycznego:
mapIntInt := map[int]int{10: 100, 20: 100, 30: 1000}
mapIntString := map[int]string{10: "foo", 20: "bar", 30: "baz"}
mapStringInt := map[string]int{"foo": 10, "bar": 20, "baz": 30}
mapStringString := map[string]string{"foo": "one", "bar": "two", "baz": "three"}
Ten sam kod, ale z typami Zmiennych:
var mapIntInt = map[int]int{10: 100, 20: 100, 30: 1000}
var mapIntString = map[int]string{10: "foo", 20: "bar", 30: "baz"}
var mapStringInt = map[string]int{"foo": 10, "bar": 20, "baz": 30}
var mapStringString = map[string]string{"foo": "one", "bar": "two", "baz": "three"}
Możesz także dołączyć własne struktury do mapy:
Możesz użyć niestandardowych typów jako wartości:
// Custom struct types
type Person struct {
FirstName, LastName string
}
var mapStringPerson = map[string]Person{
"john": Person{"John", "Doe"},
"jane": Person{"Jane", "Doe"}}
mapStringPerson := map[string]Person{
"john": Person{"John", "Doe"},
"jane": Person{"Jane", "Doe"}}
Twoja struktura może być również kluczem do mapy:
type RouteHit struct {
Domain string
Route string
}
var hitMap = map[RouteHit]int{
RouteHit{"example.com","/home"}: 1,
RouteHit{"example.com","/help"}: 2}
hitMap := map[RouteHit]int{
RouteHit{"example.com","/home"}: 1,
RouteHit{"example.com","/help"}: 2}
Możesz stworzyć pustą mapę po prostu nie wpisując żadnej wartości w nawiasach {}
.
mapIntInt := map[int]int{}
mapIntString := map[int]string{}
mapStringInt := map[string]int{}
mapStringString := map[string]string{}
mapStringPerson := map[string]Person{}
Możesz tworzyć mapę i używać jej bezpośrednio, bez potrzeby przypisywania jej do zmiennej. Musisz jednak podać zarówno deklarację, jak i treść.
// using a map as argument for fmt.Println()
fmt.Println(map[string]string{
"FirstName": "John",
"LastName": "Doe",
"Age": "30"})
// equivalent to
data := map[string]string{
"FirstName": "John",
"LastName": "Doe",
"Age": "30"}
fmt.Println(data)
Zero wartości mapy
Wartość zerowa map
wynosi nil
i ma długość 0
.
var m map[string]string
fmt.Println(m == nil) // true
fmt.Println(len(m) ==0) // true
Mapa nil
nie ma kluczy ani kluczy nie można dodawać. Mapa nil
zachowuje się jak pusta mapa, jeśli zostanie odczytana z, ale powoduje panikę w czasie wykonywania, jeśli jest zapisana.
var m map[string]string
// reading
m["foo"] == "" // true. Remember "" is the zero value for a string
_, ok = m["foo"] // ok == false
// writing
m["foo"] = "bar" // panic: assignment to entry in nil map
Nie powinieneś próbować czytać ani zapisywać map o zerowej wartości. Zamiast tego zainicjuj mapę (z make
lub przypisaniem) przed użyciem.
var m map[string]string
m = make(map[string]string) // OR m = map[string]string{}
m["foo"] = "bar"
Iteracja elementów mapy
import fmt
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for key, value := range people {
fmt.Println("Name:", key, "Age:", value)
}
Pamiętaj, że podczas iteracji po mapie za pomocą pętli zasięgu kolejność iteracji nie jest określona i nie ma gwarancji, że będzie taka sama od jednej iteracji do następnej.
Możesz także odrzucić klucze lub wartości mapy, jeśli chcesz po prostu złapać klucze lub po prostu złapać wartości.
Iteracja klawiszy mapy
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for key, _ := range people {
fmt.Println("Name:", key)
}
Jeśli szukasz tylko kluczy, ponieważ są one pierwszą wartością, możesz po prostu upuścić znak podkreślenia:
for key := range people {
fmt.Println("Name:", key)
}
Pamiętaj, że podczas iteracji po mapie za pomocą pętli zasięgu kolejność iteracji nie jest określona i nie ma gwarancji, że będzie taka sama od jednej iteracji do następnej.
Usuwanie elementu mapy
delete
wbudowana funkcja usuwa element z określonego klucza z mapą.
people := map[string]int{"john": 30, "jane": 29}
fmt.Println(people) // map[john:30 jane:29]
delete(people, "john")
fmt.Println(people) // map[jane:29]
Jeśli map
jest nil
lub nie ma takiego elementu, delete
nie ma wpływu.
people := map[string]int{"john": 30, "jane": 29}
fmt.Println(people) // map[john:30 jane:29]
delete(people, "notfound")
fmt.Println(people) // map[john:30 jane:29]
var something map[string]int
delete(something, "notfound") // no-op
Liczenie elementów mapy
Wbudowana funkcja len
zwraca liczbę elementów na map
m := map[string]int{}
len(m) // 0
m["foo"] = 1
len(m) // 1
Jeśli zmienna wskazuje mapę nil
, len
zwraca 0.
var m map[string]int
len(m) // 0
Jednoczesny dostęp do map
Mapy w go nie są bezpieczne dla współbieżności. Musisz mieć blokadę, aby czytać i pisać na nich, jeśli będziesz mieć do nich dostęp jednocześnie. Zwykle najlepszą opcją jest użycie sync.RWMutex
ponieważ możesz mieć blokady odczytu i zapisu. sync.Mutex
jednak również użyć sync.Mutex
.
type RWMap struct {
sync.RWMutex
m map[string]int
}
// Get is a wrapper for getting the value from the underlying map
func (r RWMap) Get(key string) int {
r.RLock()
defer r.RUnlock()
return r.m[key]
}
// Set is a wrapper for setting the value of a key in the underlying map
func (r RWMap) Set(key string, val int) {
r.Lock()
defer r.Unlock()
r.m[key] = val
}
// Inc increases the value in the RWMap for a key.
// This is more pleasant than r.Set(key, r.Get(key)++)
func (r RWMap) Inc(key string) {
r.Lock()
defer r.Unlock()
r.m[key]++
}
func main() {
// Init
counter := RWMap{m: make(map[string]int)}
// Get a Read Lock
counter.RLock()
_ = counter.["Key"]
counter.RUnlock()
// the above could be replaced with
_ = counter.Get("Key")
// Get a write Lock
counter.Lock()
counter.m["some_key"]++
counter.Unlock()
// above would need to be written as
counter.Inc("some_key")
}
Kompromis funkcji opakowania jest między publicznym dostępem do podstawowej mapy i prawidłowym użyciem odpowiednich blokad.
Tworzenie map z wycinkami jako wartościami
m := make(map[string][]int)
Uzyskanie dostępu do nieistniejącego klucza zwróci wartość zerową jako wartość. Ponieważ wycinki zerowe działają jak wycinki zerowej długości, gdy są używane z append
lub innymi wbudowanymi funkcjami, zwykle nie trzeba sprawdzać, czy istnieje klucz:
// m["key1"] == nil && len(m["key1"]) == 0
m["key1"] = append(m["key1"], 1)
// len(m["key1"]) == 1
Usunięcie klucza z mapy powoduje powrót klucza do zera:
delete(m, "key1")
// m["key1"] == nil
Sprawdź element na mapie
Aby uzyskać wartość z mapy, wystarczy zrobić coś takiego: 00
value := mapName[ key ]
Jeśli mapa zawiera klucz, zwraca odpowiednią wartość.
Jeśli nie, to zwraca zero wartość typu wartości mapie'S ( 0
jeśli mapa int
wartości, ""
jeśli mapa string
wartości ...)
m := map[string]string{"foo": "foo_value", "bar": ""}
k := m["foo"] // returns "foo_value" since that is the value stored in the map
k2 := m["bar"] // returns "" since that is the value stored in the map
k3 := m["nop"] // returns "" since the key does not exist, and "" is the string type's zero value
Aby rozróżnić puste wartości od nieistniejących kluczy, możesz użyć drugiej zwróconej wartości dostępu do mapy (używając podobnej value, hasKey := map["key"]
).
Ta druga wartość jest boolean
i będzie to:
-
true
gdy wartość znajduje się na mapie, -
false
gdy mapa nie zawiera podanego klucza.
Spójrz na następujący przykład:
value, hasKey = m[ key ]
if hasKey {
// the map contains the given key, so we can safely use the value
// If value is zero-value, it's because the zero-value was pushed to the map
} else {
// The map does not have the given key
// the value will be the zero-value of the map's type
}
Iterowanie wartości mapy
people := map[string]int{
"john": 30,
"jane": 29,
"mark": 11,
}
for _, value := range people {
fmt.Println("Age:", value)
}
Pamiętaj, że podczas iteracji po mapie za pomocą pętli zasięgu kolejność iteracji nie jest określona i nie ma gwarancji, że będzie taka sama od jednej iteracji do następnej.
Skopiuj mapę
Podobnie jak wycinki, mapy zawierają odniesienia do podstawowej struktury danych. Przypisując jego wartość do innej zmiennej, przekazane zostanie tylko odwołanie. Aby skopiować mapę, konieczne jest utworzenie innej mapy i skopiowanie każdej wartości:
// Create the original map
originalMap := make(map[string]int)
originalMap["one"] = 1
originalMap["two"] = 2
// Create the target map
targetMap := make(map[string]int)
// Copy from the original map to the target map
for key, value := range originalMap {
targetMap[key] = value
}
Używanie mapy jako zestawu
Niektóre języki mają natywną strukturę zestawów. Aby utworzyć zestaw w Go, najlepszą praktyką jest użycie mapy od typu wartości zestawu do pustej struktury ( map[Type]struct{}
).
Na przykład z ciągami:
// To initialize a set of strings:
greetings := map[string]struct{}{
"hi": {},
"hello": {},
}
// To delete a value:
delete(greetings, "hi")
// To add a value:
greetings["hey"] = struct{}{}
// To check if a value is in the set:
if _, ok := greetings["hey"]; ok {
fmt.Println("hey is in greetings")
}