Sök…


Introduktion

Kartor är datatyper som används för att lagra oordnade nyckelvärdespar, så att det är mycket effektivt att slå upp värdet associerat med en given nyckel. Nycklar är unika. Den underliggande datastrukturen växer efter behov för att rymma nya element, så programmeraren behöver inte oroa sig för minneshantering. De liknar det som andra språk kallar hashtabeller, ordböcker eller associerande matriser.

Syntax

  • var mapName map [KeyType] ValueType // deklarera en karta
  • var mapName = map [KeyType] ValueType {} // förklara och tilldela en tom karta
  • var mapName = map [KeyType] ValueType {key1: val1, key2: val2} // deklarera och tilldela en karta
  • mapName: = make (map [KeyType] ValueType) // deklarera och initialisera standardstorlekskarta
  • mapName: = make (karta [KeyType] ValueType, length) // deklarera och initialisera längdstorlekskarta
  • mapName: = map [KeyType] ValueType {} // auto-deklarera och tilldela en tom karta med: =
  • mapName: = map [KeyType] ValueType {key1: value1, key2: value2} // auto-deklarera och tilldela en karta med: =
  • värde: = mapName [nyckel] // Få värde för nyckel
  • value, hasKey: = mapName [key] // Hämta värde per nyckel, 'hasKey' är 'true' om nyckel finns i kartan
  • mapName [key] = värde // Ställ in värde för nyckel

Anmärkningar

Go finns en inbyggd map typ som implementerar en hash-tabell. Kartor är Gos inbyggda associativa datatyp (även kallad hashes eller ordböcker på andra språk).

Förklaring och initialisering av en karta

Du definierar en karta med hjälp av sökord map , följt av de typer av sina nycklar och dess värden:

// 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

Kartor är referenstyper, och när de väl definierats har de ett nollvärdenil . Skrivningar till nollkartor kommer att få panik och läsningar kommer alltid att returnera nollvärdet.

För att initialisera en karta använder du make funktionen:

m := make(map[string]int)

Med tvåparameterns form av make är det möjligt att ange en initial inmatningskapacitet för kartan och åsidosätta standardkapaciteten:

m := make(map[string]int, 30)

Alternativt kan du förklara en karta, initiera den till dess nollvärde och sedan tilldela ett bokstavsvärde till det senare, vilket hjälper om du marshalerar strukturen till json och därmed producerar en tom karta vid retur.

m := make(map[string]int, 0)

Du kan också skapa en karta och ställa in dess initiala värde med lockiga parenteser ( {} ).

var m map[string]int = map[string]int{"Foo": 20, "Bar": 30}

fmt.Println(m["Foo"]) // outputs 20

Alla följande påståenden resulterar i att variabeln är bunden till samma värde.

// 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{}

Vi kan också använda en bokstavlig karta för att skapa en ny karta med några initiala nyckel- / värdepar .

Nyckeltypen kan vara vilken som helst jämförbar typ; särskilt utesluter detta funktioner, kartor och skivor . Värdetypen kan vara valfri typ, inklusive anpassade typer eller 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{}

Skapa en karta

Man kan förklara och initiera en karta i ett enda uttalande med hjälp av en sammansatt bokstav .

Med automatisk typ kortvariabel deklaration:

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

Samma kod, men med variabeltyper:

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

Du kan också inkludera dina egna strukturer på en karta:

Du kan använda anpassade typer som värde:

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

Din struktur kan också vara nyckeln till kartan:

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}

Du kan skapa en tom karta helt enkelt genom att inte ange något värde inom parentes {} .

mapIntInt := map[int]int{}
mapIntString := map[int]string{}
mapStringInt := map[string]int{}
mapStringString := map[string]string{}
mapStringPerson := map[string]Person{}

Du kan skapa och använda en karta direkt utan att behöva tilldela den till en variabel. Du måste dock ange både deklarationen och innehållet.

// 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)

Nollvärde på en karta

Nollvärdet på en map är nil och har en längd på 0 .

var m map[string]string
fmt.Println(m == nil) // true
fmt.Println(len(m) ==0) // true

En nil har inga nycklar eller kan inte läggas till nycklar. En nil uppför sig som en tom karta om den läses från men orsakar panik för körning om den skrivs till.

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

Du bör inte försöka läsa från eller skriva till en karta med nollvärde. Inleda istället kartan (med make eller tilldelning) innan du använder den.

var m map[string]string
m = make(map[string]string) // OR m = map[string]string{}
m["foo"] = "bar"

Iterera elementen på en karta

import fmt

people := map[string]int{
  "john": 30,
  "jane": 29,
  "mark": 11,
}

for key, value := range people {
  fmt.Println("Name:", key, "Age:", value)
}

Observera att när iterering över en karta med en avståndsslinga är iterationsordningen inte specificerad och garanteras inte vara densamma från en iteration till nästa.

Du kan också kassera antingen nycklarna eller värdena på kartan om du bara vill ta tag i knapparna eller bara greppa värden.

Iterera nycklarna på en karta

people := map[string]int{
  "john": 30,
  "jane": 29,
  "mark": 11,
}

for key, _ := range people {
  fmt.Println("Name:", key)
}

Om du bara letar efter nycklarna, eftersom de är det första värdet, kan du helt enkelt släppa understrecket:

for key := range people {
  fmt.Println("Name:", key)
}

Observera att när iterering över en karta med en avståndsslinga är iterationsordningen inte specificerad och garanteras inte vara densamma från en iteration till nästa.

Radera ett kartelement

Den delete inbyggd funktion tar bort elementet med den angivna nyckeln från en karta.

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]

Om map är nil eller det inte finns något sådant element har delete ingen effekt.

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

Räkna kartelement

Den inbyggda funktionen len returnerar antalet element på en map

m := map[string]int{}
len(m) // 0

m["foo"] = 1
len(m) // 1

Om en variabel pekar på en nil karta, returnerar len 0.

var m map[string]int
len(m) // 0

Samtidig åtkomst av kartor

Kartor i gång är inte säkra för samtidighet. Du måste ta ett lås för att läsa och skriva om dem om du kommer åt dem samtidigt. Vanligtvis är det bästa alternativet att använda sync.RWMutex eftersom du kan ha läs- och skrivlås. Men en sync.Mutex kan också användas.

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

Avvägningen av omslagsfunktionerna är mellan allmänhetens åtkomst till den underliggande kartan och att använda lämpliga lås korrekt.

Skapa kartor med skivor som värden

m := make(map[string][]int)

Åtkomst till en icke-existerande nyckel kommer att returnera en nollskiva som ett värde. Eftersom nollskivor fungerar som skivor med noll längd när de används med append eller andra inbyggda funktioner behöver du normalt inte kontrollera om en nyckel finns:

// m["key1"] == nil && len(m["key1"]) == 0
m["key1"] = append(m["key1"], 1)
// len(m["key1"]) == 1

Om du tar bort en nyckel från kartan återgår nyckeln till en nollskiva:

delete(m, "key1")
// m["key1"] == nil

Sök efter element på en karta

För att få ett värde från kartan måste du bara göra något som: 00

value := mapName[ key ]

Om kartan innehåller nyckeln returnerar den motsvarande värde.
Om inte, returnerar det nollvärdet för kartans värdetyp ( 0 om kartan med int värden, "" om kartan över string ...)

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

För att skilja mellan tomma värden och icke-existerande nycklar kan du använda det andra returnerade värdet på kartåtkomst (med samma value, hasKey := map["key"] ).

Detta andra värde är boolean och kommer att vara:

  • true när värdet finns på kartan,
  • false när kartan inte innehåller den angivna nyckeln.

Titta på följande exempel:

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
}

Iterera värdena på en karta

people := map[string]int{
  "john": 30,
  "jane": 29,
  "mark": 11,
}

for _, value := range people {
  fmt.Println("Age:", value)
}

Observera att när iterering över en karta med en avståndsslinga är iterationsordningen inte specificerad och garanteras inte vara densamma från en iteration till nästa.

Kopiera en karta

Liksom skivor har kartor referenser till en underliggande datastruktur. Så genom att tilldela dess värde till en annan variabel kommer endast referensen att skickas. För att kopiera kartan är det nödvändigt att skapa en ny karta och kopiera varje värde:

// 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
}

Använda en karta som en uppsättning

Vissa språk har en ursprunglig struktur för uppsättningar. För att göra en uppsättning i Go är det bästa sättet att använda en karta från värdetyp för uppsättningen till en tom struktur ( map[Type]struct{} ).

Till exempel med strängar:

// 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
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow