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")
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow