Buscar..


Introducción

Los mapas son tipos de datos utilizados para almacenar pares clave-valor no ordenados, de modo que buscar el valor asociado a una clave dada es muy eficiente. Las llaves son únicas. La estructura de datos subyacente crece según sea necesario para acomodar nuevos elementos, por lo que el programador no tiene que preocuparse por la administración de la memoria. Son similares a lo que otros lenguajes denominan tablas hash, diccionarios o matrices asociativas.

Sintaxis

  • var mapName map [KeyType] ValueType // declara un mapa
  • var mapName = map [KeyType] ValueType {} // declara y asigna un mapa vacío
  • var mapName = map [KeyType] ValueType {key1: val1, key2: val2} // declara y asigna un Map
  • mapName: = make (map [KeyType] ValueType) // declara e inicializa el mapa de tamaño predeterminado
  • mapName: = make (map [KeyType] ValueType, length) // declara e inicializa el mapa de tamaño de longitud
  • mapName: = map [KeyType] ValueType {} // auto-declara y asigna un mapa vacío con: =
  • mapName: = map [KeyType] ValueType {key1: value1, key2: value2} // declarar automáticamente y asignar un mapa con: =
  • valor: = mapName [clave] // Obtener valor por clave
  • value, hasKey: = mapName [key] // Obtener valor por clave, 'hasKey' es 'true' si la clave existe en el mapa
  • mapName [clave] = valor // Establecer valor por clave

Observaciones

Go proporciona un tipo de map incorporado que implementa una tabla hash . Los mapas son el tipo de datos asociativos incorporados de Go (también llamados hashes o diccionarios en otros idiomas).

Declarar e inicializar un mapa

Usted define un mapa usando el map palabras clave, seguido de los tipos de sus claves y sus valores:

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

Los mapas son tipos de referencia y, una vez definidos, tienen un valor cero de nil . Las escrituras en mapas nulos entrarán en pánico y las lecturas siempre devolverán el valor cero.

Para inicializar un mapa, use la función make :

m := make(map[string]int)

Con la forma de make de dos parámetros, es posible especificar una capacidad de entrada inicial para el mapa, anulando la capacidad predeterminada:

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

Alternativamente, puede declarar un mapa, inicializarlo a su valor cero, y luego asignarle un valor literal más tarde, lo que ayuda si calibra la estructura en json para producir un mapa vacío en el retorno.

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

También puede hacer un mapa y establecer su valor inicial entre llaves ( {} ).

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

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

Todas las siguientes declaraciones dan como resultado que la variable se enlaza al mismo valor.

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

También podemos usar un mapa literal para crear un nuevo mapa con algunos pares de clave / valor iniciales .

El tipo de clave puede ser cualquier tipo comparable ; En particular, esto excluye funciones, mapas y segmentos . El tipo de valor puede ser cualquier tipo, incluidos los tipos personalizados o la 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{}

Creando un mapa

Uno puede declarar e inicializar un mapa en una sola declaración usando un literal compuesto .

Usando el tipo automático de declaración de variable corta:

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

El mismo código, pero con tipos de variables:

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

También puedes incluir tus propias estructuras en un mapa:

Puedes usar tipos personalizados como valor:

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

Tu estructura también puede ser la clave del mapa:

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}

Puede crear un mapa vacío simplemente no ingresando ningún valor entre los corchetes {} .

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

Puede crear y usar un mapa directamente, sin la necesidad de asignarlo a una variable. Sin embargo, deberá especificar tanto la declaración como el contenido.

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

Valor cero de un mapa

El valor cero de un map es nil y tiene una longitud de 0 .

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

Un mapa nil no tiene claves ni se pueden agregar claves. Un mapa nil comporta como un mapa vacío si se lee desde, pero provoca un pánico en el tiempo de ejecución si se escribe.

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

No debe intentar leer o escribir en un mapa de valor cero. En su lugar, inicialice el mapa (con make o asignación) antes de usarlo.

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

Iterando los elementos de un mapa.

import fmt

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

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

Tenga en cuenta que al iterar sobre un mapa con un bucle de rango, el orden de iteración no se especifica y no se garantiza que sea igual de una iteración a la siguiente.

También puede descartar las claves o los valores del mapa, si está buscando simplemente agarrar las claves o simplemente tomar los valores.

Iterando las teclas de un mapa.

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

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

Si solo está buscando las claves, ya que son el primer valor, simplemente puede colocar el guión bajo:

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

Tenga en cuenta que al iterar sobre un mapa con un bucle de rango, el orden de iteración no se especifica y no se garantiza que sea igual de una iteración a la siguiente.

Eliminar un elemento del mapa

La función incorporada de delete elimina el elemento con la clave especificada de un mapa.

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]

Si el map es nil o no existe tal elemento, delete no tiene efecto.

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

Contando elementos del mapa

La función incorporada len devuelve el número de elementos en un map

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

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

Si una variable apunta a un mapa nil , len devuelve 0.

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

Acceso concurrente de mapas

Los mapas en go no son seguros para la concurrencia. Debe tomar un candado para leer y escribir en ellos si va a acceder a ellos al mismo tiempo. Generalmente, la mejor opción es usar sync.RWMutex porque puede tener bloqueos de lectura y escritura. Sin embargo, un sync.Mutex también podría ser utilizado.

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

La compensación de las funciones de envoltura es entre el acceso público del mapa subyacente y el uso correcto de los bloqueos apropiados.

Creación de mapas con cortes como valores.

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

El acceso a una clave no existente devolverá una porción nula como un valor. Dado que los segmentos nulos actúan como segmentos de longitud cero cuando se usan con funciones append u otras funciones incorporadas, normalmente no es necesario verificar para ver si existe una clave:

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

Al eliminar una clave del mapa, la clave vuelve a ser nula:

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

Verificar elemento en un mapa

Para obtener un valor del mapa, solo tienes que hacer algo como: 00

value := mapName[ key ]

Si el mapa contiene la clave, devuelve el valor correspondiente.
Si no, devuelve el valor cero del tipo de valor del mapa ( 0 si es un mapa de valores int , "" si es un mapa de valores de 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

Para diferenciar entre valores vacíos y claves no existentes, puede usar el segundo valor devuelto del acceso al mapa (usando el value, hasKey := map["key"] like value, hasKey := map["key"] ).

Este segundo valor es de tipo boolean , y será:

  • true cuando el valor está en el mapa,
  • false cuando el mapa no contiene la clave dada.

Mira el siguiente ejemplo:

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
}

Iterando los valores de un mapa.

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

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

Tenga en cuenta que al iterar sobre un mapa con un bucle de rango, el orden de iteración no se especifica y no se garantiza que sea igual de una iteración a la siguiente.

Copiar un mapa

Al igual que los cortes, los mapas contienen referencias a una estructura de datos subyacente. Entonces, al asignar su valor a otra variable, solo se pasará la referencia. Para copiar el mapa, es necesario crear otro mapa y copiar cada valor:

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

Usando un mapa como conjunto

Algunos idiomas tienen una estructura nativa para conjuntos. Para hacer un conjunto en Go, se recomienda usar un mapa del tipo de valor del conjunto a una estructura vacía ( map[Type]struct{} ).

Por ejemplo, con cuerdas:

// 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
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow