Zoeken…


Invoering

Kaarten zijn gegevenstypen die worden gebruikt voor het opslaan van ongeordende sleutel / waarde-paren, zodat het opzoeken van de waarde die aan een bepaalde sleutel is gekoppeld, zeer efficiënt is. Sleutels zijn uniek. De onderliggende gegevensstructuur groeit naar behoefte om nieuwe elementen op te nemen, zodat de programmeur zich geen zorgen hoeft te maken over geheugenbeheer. Ze zijn vergelijkbaar met wat andere talen hashtabellen, woordenboeken of associatieve arrays noemen.

Syntaxis

  • var mapName map [KeyType] ValueType // declareer een kaart
  • var mapName = map [KeyType] ValueType {} // declareer en wijs een lege kaart toe
  • var mapName = map [KeyType] ValueType {key1: val1, key2: val2} // declareer en wijs een kaart toe
  • mapName: = make (map [KeyType] ValueType) // declareer en initialiseer de standaardgroottekaart
  • mapName: = make (map [KeyType] ValueType, lengte) // declareren en initialiseren lengte grootte kaart
  • mapName: = map [KeyType] ValueType {} // auto-declareer en wijs een lege kaart toe met: =
  • mapName: = map [KeyType] ValueType {key1: value1, key2: value2} // automatisch aangeven en een kaart toewijzen met: =
  • value: = mapName [key] // Krijg waarde per key
  • value, hasKey: = mapName [key] // Krijg waarde per key, 'hasKey' is 'true' als de sleutel bestaat in map
  • mapName [key] = waarde // Stel waarde per sleutel in

Opmerkingen

Go verschaft een ingebouwde map -type dat implementeert een hashtabel. Kaarten zijn het ingebouwde associatieve gegevenstype van Go (ook hashes of woordenboeken in andere talen genoemd).

Een kaart declareren en initialiseren

U definieert een kaart met behulp van het trefwoord map , gevolgd door het vormen van de sleutels en de waarden:

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

Kaarten zijn referentietypen en eenmaal gedefinieerd hebben ze een nulwaarde van nil . Schrijft naar nulkaarten raakt in paniek en lezen geeft altijd de nulwaarde terug.

Gebruik de make functie make een kaart te initialiseren:

m := make(map[string]int)

Met de vorm met twee parameters van make is het mogelijk om een initiële invoercapaciteit voor de kaart op te geven, die de standaardcapaciteit overschrijft:

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

Als alternatief kun je een kaart declareren, deze op de nulwaarde initialiseren en er later een letterlijke waarde aan toewijzen, wat helpt als je de struct in json zet en daarmee een lege kaart produceert.

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

U kunt ook een kaart maken en de beginwaarde instellen met accolades ( {} ).

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

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

Alle volgende uitspraken leiden ertoe dat de variabele aan dezelfde waarde wordt gebonden.

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

We kunnen ook een letterlijke kaart gebruiken om een nieuwe kaart te maken met enkele initiële sleutel / waarde-paren .

Het sleuteltype kan elk vergelijkbaar type zijn; dit sluit met name functies, kaarten en segmenten uit . Het waardetype kan elk type zijn, inclusief aangepaste typen of 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{}

Een kaart maken

Men kan een kaart in een enkele verklaring declareren en initialiseren met behulp van een samengestelde letterlijke waarde .

Automatisch type gebruiken Korte variabele declaratie:

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

Dezelfde code, maar met variabeletypes:

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

Je kunt ook je eigen structuren in een kaart opnemen:

U kunt aangepaste typen als waarde gebruiken:

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

Je struct kan ook de sleutel tot de kaart zijn:

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}

U kunt een lege kaart maken door eenvoudigweg geen waarde tussen haakjes {} .

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

U kunt een kaart rechtstreeks maken en gebruiken, zonder deze aan een variabele toe te wijzen. U moet echter zowel de aangifte als de inhoud opgeven.

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

Nulwaarde van een kaart

De nulwaarde van een map is nil en heeft een lengte van 0 .

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

Een nil heeft geen sleutels en er kunnen geen sleutels worden toegevoegd. Een nil gedraagt zich als een lege kaart als deze wordt gelezen van, maar veroorzaakt een runtime-paniek als er naar wordt geschreven.

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

Probeer niet te lezen van of te schrijven naar een kaart met nulwaarde. Initialiseer in plaats daarvan de kaart (met make of opdracht) voordat u deze gebruikt.

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

De elementen van een kaart herhalen

import fmt

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

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

Merk op dat bij iteratie over een kaart met een bereiklus, de iteratievolgorde niet is gespecificeerd en niet gegarandeerd is dat deze van de ene iteratie tot de volgende hetzelfde is.

U kunt ook de sleutels of de waarden van de kaart weggooien als u alleen sleutels wilt pakken of alleen waarden wilt pakken.

De toetsen van een kaart herhalen

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

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

Als u alleen op zoek bent naar de toetsen, aangezien deze de eerste waarde zijn, kunt u eenvoudig het onderstrepingsteken verwijderen:

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

Merk op dat bij iteratie over een kaart met een bereiklus, de iteratievolgorde niet is gespecificeerd en niet gegarandeerd is dat deze van de ene iteratie tot de volgende hetzelfde is.

Een kaartelement verwijderen

De delete ingebouwde functie verwijdert het element met de opgegeven sleutel van een kaart.

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]

Als de map nil of een dergelijk element ontbreekt, heeft delete geen effect.

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

Kaartelementen tellen

De ingebouwde functie len geeft het aantal elementen op een map

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

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

Als een variabele naar een nil verwijst, geeft len 0 terug.

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

Gelijktijdige toegang tot kaarten

Kaarten die onderweg zijn, zijn niet veilig voor gelijktijdigheid. U moet een slot nemen om ze te lezen en erop te schrijven als u ze tegelijkertijd wilt gebruiken. Meestal is de beste optie om sync.RWMutex te gebruiken omdat u lees- en schrijfvergrendelingen kunt hebben. Een sync.Mutex kan echter ook worden gebruikt.

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

De afweging van de wrapper-functies is tussen de openbare toegang van de onderliggende kaart en het juiste gebruik van de juiste sloten.

Kaarten maken met segmenten als waarden

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

Toegang tot een niet-bestaande sleutel retourneert een nul-segment als een waarde. Aangezien nul-segmenten werken als segmenten van nul lengte bij gebruik met append of andere ingebouwde functies, hoeft u normaal gesproken niet te controleren of er een sleutel bestaat:

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

Als u een sleutel uit de kaart verwijdert, wordt de sleutel teruggezet naar een nul-segment:

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

Controleer op een element in een kaart

Om een waarde van de kaart te krijgen, moet je gewoon iets doen als: 00

value := mapName[ key ]

Als de kaart de sleutel bevat, retourneert deze de bijbehorende waarde.
Als dit niet het geval is, retourneert het de nulwaarde van het waardetype van de kaart ( 0 als map met int waarden, "" als map met 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

Om onderscheid te maken tussen lege waarden en niet-bestaande sleutels, kunt u de tweede geretourneerde waarde van de value, hasKey := map["key"] gebruiken (met dezelfde value, hasKey := map["key"] ).

Deze tweede waarde is boolean getypt en zal zijn:

  • true wanneer de waarde op de kaart staat,
  • false wanneer de kaart niet de gegeven sleutel bevat.

Bekijk het volgende voorbeeld:

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
}

De waarden van een kaart herhalen

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

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

Merk op dat bij iteratie over een kaart met een bereiklus, de iteratievolgorde niet is gespecificeerd en niet gegarandeerd is dat deze van de ene iteratie tot de volgende hetzelfde is.

Kopieer een kaart

Net als segmenten bevatten kaarten verwijzingen naar een onderliggende gegevensstructuur. Dus door de waarde toe te wijzen aan een andere variabele, wordt alleen de referentie doorgegeven. Om de kaart te kopiëren, is het noodzakelijk om een andere kaart te maken en elke waarde te kopiëren:

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

Een kaart als een set gebruiken

Sommige talen hebben een eigen structuur voor sets. Om een set in Go te maken, is het best om een kaart te gebruiken van het waardetype van de set naar een lege struct ( map[Type]struct{} ).

Bijvoorbeeld met tekenreeksen:

// 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
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow