Поиск…


Вступление

Карты - это типы данных, используемые для хранения неупорядоченных пар ключ-значение, так что поиск значения, связанного с данным ключом, очень эффективен. Ключи уникальны. Основная структура данных растет по мере необходимости для размещения новых элементов, поэтому программисту не нужно беспокоиться об управлении памятью. Они похожи на то, что другие языки называют хэш-таблицами, словарями или ассоциативными массивами.

Синтаксис

  • var mapName map [KeyType] ValueType // объявляет карту
  • var mapName = map [KeyType] ValueType {} // объявлять и назначать пустую карту
  • var mapName = map [KeyType] ValueType {key1: val1, key2: val2} // объявлять и назначать карту
  • mapName: = make (map [KeyType] ValueType) // объявлять и инициализировать карту размера по умолчанию
  • mapName: = make (map [KeyType] ValueType, length) // объявлять и инициализировать карту размера длины
  • mapName: = map [KeyType] ValueType {} // auto-declare и назначить пустую карту с: =
  • mapName: = map [KeyType] ValueType {key1: value1, key2: value2} // auto-declare и назначить карту с: =
  • value: = mapName [key] // Получить значение по ключу
  • value, hasKey: = mapName [key] // Получить значение по ключу, hasKey - true, если ключ существует на карте
  • mapName [ключ] = значение // Установить значение по ключу

замечания

Go предоставляет встроенный тип map который реализует хеш-таблицу . Карты - это встроенный ассоциативный тип данных Go (также называемый хешами или словарями на других языках).

Объявление и инициализация карты

Вы определяете карту , используя ключевое слово map , а затем типов его ключей и его значения:

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

Карты являются ссылочными типами, и после определения они имеют нулевое значение nil . Записывает в карты nil панику, и чтение всегда возвращает нулевое значение.

Чтобы инициализировать карту, используйте функцию make :

m := make(map[string]int)

С помощью двухпараметрической формы make можно указать начальную емкость ввода для карты, переопределяя емкость по умолчанию:

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

Кроме того, вы можете объявить карту, инициализируя ее нулевым значением, а затем присвоить ей литеральное значение позже, что поможет, если вы создадите структуру в json, тем самым создавая пустую карту при возврате.

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

Вы также можете создать карту и установить ее начальное значение с фигурными скобками ( {} ).

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

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

Все следующие утверждения приводят к тому, что переменная привязана к одному и тому же значению.

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

Мы также можем использовать литерал карты для создания новой карты с некоторыми начальными парами ключ / значение .

Тип ключа может быть любым сопоставимым типом; в частности, это исключает функции, карты и срезы . Тип значения может быть любого типа, включая настраиваемые типы или 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{}

Создание карты

Можно объявить и инициализировать карту в одном выражении, используя составной литерал .

Использование автоматического типа Объявление коротких переменных:

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

Тот же код, но с переменными типами:

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

Вы также можете включить свои собственные структуры на карте:

Вы можете использовать нестандартные типы в качестве значения:

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

Ваша структура также может быть ключом к карте:

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}

Вы можете создать пустую карту, просто не введя никакого значения в скобки {} .

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

Вы можете создавать и использовать карту напрямую, без необходимости присваивать ее переменной. Однако вам нужно будет указать как объявление, так и контент.

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

Нулевое значение карты

Нулевое значение map равно nil и имеет длину 0 .

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

В карте nil нет ключей и не могут быть добавлены ключи. Карта nil ведет себя как пустая карта, если она читается, но вызывает панику при запуске, если она записана.

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

Вы не должны пытаться читать или записывать карту нулевого значения. Вместо этого инициализируйте карту (с make или присваиванием) перед ее использованием.

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

Итерация элементов карты

import fmt

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

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

Обратите внимание, что при итерации по карте с циклом диапазона порядок итерации не указан и не может быть одинаковым с одной итерации на другую.

Вы также можете отбросить либо ключи, либо значения карты, если вы хотите просто захватить ключи или просто захватить значения.

Итерация ключей карты

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

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

Если вы просто ищете ключи, так как они являются первым значением, вы можете просто выделить подчеркивание:

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

Обратите внимание, что при итерации по карте с циклом диапазона порядок итерации не указан и не может быть одинаковым с одной итерации на другую.

Удаление элемента карты

Функция « delete удаляет элемент с указанным ключом с карты.

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]

Если map равна nil или нет такого элемента, delete не имеет эффекта.

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

Подсчет элементов карты

Встроенная функция len возвращает количество элементов на map

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

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

Если переменная указывает на карту nil , то len возвращает 0.

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

Параллельный доступ к картам

Карты в режиме go небезопасны для параллелизма. Вы должны сделать блокировку, чтобы читать и писать на них, если вы будете обращаться к ним одновременно. Обычно лучшим вариантом является использование sync.RWMutex поскольку вы можете иметь блокировки чтения и записи. Однако также можно использовать 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")
}

Комплимент функций обертки находится между общедоступным доступом к базовой карте и правильными правильными блокировками.

Создание карт с фрагментами как значения

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

Доступ к несуществующему ключу будет возвращать нулевой фрагмент в качестве значения. Поскольку нильские срезы действуют как срезы нулевой длины при использовании с append или другими встроенными функциями, вам обычно не нужно проверять, существует ли ключ:

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

Удаление ключа с карты устанавливает ключ обратно на нулевой фрагмент:

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

Проверить элемент на карте

Чтобы получить значение с карты, вам просто нужно сделать что-то вроде: 00

value := mapName[ key ]

Если карта содержит ключ, она возвращает соответствующее значение.
Если нет, он возвращает нулевое значение типа значения карты ( 0 если карта значений int , "" если карта значений 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

Чтобы различать пустые значения и несуществующие ключи, вы можете использовать второе возвращаемое значение доступа к карте (используя такое же value, hasKey := map["key"] ).

Это второе значение boolean , и будет:

  • true когда значение находится на карте,
  • false если карта не содержит данный ключ.

Посмотрите на следующий пример:

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
}

Итерирование значений карты

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

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

Обратите внимание, что при итерации по карте с циклом диапазона порядок итерации не указан и не может быть одинаковым с одной итерации на другую.

Скопировать карту

Подобно срезам, карты содержат ссылки на базовую структуру данных. Поэтому, присваивая его значение другой переменной, будет передана только эта ссылка. Чтобы скопировать карту, необходимо создать другую карту и скопировать каждое значение:

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

Использование карты в виде набора

Некоторые языки имеют собственную структуру для множеств. Чтобы сделать набор в Go, лучше всего использовать карту из типа значения набора в пустую структуру ( map[Type]struct{} ).

Например, со строками:

// 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
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow