#9 golang Хэш таблицы - Map (отображение, мапа), "ассоциативные массивы"

Здесь поговорим о хеш-таблице - она же ассоциативный массив, она же — «отображение».

Эта штука позволяет по ключу быстро получить значение. Это удобно, если у вас значений довольно много. Если бы они лежали в слайсе или в обычном массиве, вам бы пришлось все перебирать, а с помощью мэпы мы можем очень быстро (в сравнении с другими структурами) получить нужный элемент, обратившись к нему "по ключу"

Определение мэпы

// инициализация при создании
user := map[string]string{}

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

При этом по ключу в мэпе может лежать другая мэпа и т.д. (многомерность).

Что может быть ключом

Любая сравниваемая структура данных может выступать ключом мэпы (чтобы можно было понять к этому ключу вы обращаетесь или нет)

Задание значений хэш таблицы

При объявлении можно и сразу задать конкретные значения:

// инициализация при создании
userData := map[string]string{
	"name":     "Vasily",
	"lastName": "Romanov",
}
fmt.Println(userData)

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

// сразу с нужной емкостью
profile := make(map[string]string, 10)

-- при этом мы не можем применить cap() для получения вместимости, ибо в данном случае второй параметр для определяет её так же четко как для слайсов.

Через len можно получить количество элементов в мапе:

userData := map[string]string{
	"name":     "Vasily",
	"lastName": "Romanov",
}
fmt.Println(len(userData)) // 2

Обращение к элементам

Обратиться к уже лежащим в мапе элементам можно при помощи квадратных скобок:

userData := map[string]string{
	"name":     "Vasily",
	"lastName": "Romanov",
}
// если ключа нет — вернет значение по умолчанию для типа
mName := userData["middleName"]
fmt.Println("mName:", mName)

-- ВАЖНО: Если этого ключа нет в мапе, то вернется значение по умолчанию для типа значения. Про это обязательно надо помнить!

Например, если у вас мапа, в которой значения имеют тип bool, то значение по умолчанию для bool — это false. Если вернется false, то нужно как-то отличать, что вернулось — значение false, которое действительно лежит по ключу, или отсутствие ключа.


Проверка сущестования элемента по ключу

Для разрешения этой ситуации можно получить признак существования ключа, например, с использованием второй переменной при обращении к мапе:

userData := map[string]string{
	"name":     "Vasily",
	"lastName": "Romanov",
}
// проверка существования ключа
mName, mNameExist := userData["middleName"]
fmt.Println("mName:", mName, "mNameExist:", mNameExist)

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

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

// пустая переменная — только проверяем, что ключ есть
_, mNameExist := userData["middleName"]
fmt.Println("mNameExist:", mNameExist)

Удаление элементов

Значения можно удалять, передав их ключ во встроенную функцию delete():

userData := map[string]string{
	"name":     "Vasily",
	"lastName": "Romanov",
}
// удаление ключа
delete(userData, "lastName")
fmt.Printf("%#v\n", userData)

Что еще почитать

Key Words for FKN + antitotal forum (CS VSU):