Словари и хеш-таблицы в Go 1.21: подробное руководство
Словари и хеш-таблицы в Go
Что такое словарь и зачем он нужен?
Представь, что у тебя есть волшебная коробка, в которую можно положить что угодно, но чтобы достать предмет, нужно назвать его имя (ключ). Например, ты кладешь в коробку "Москва" → "Привет", "Лондон" → "Hello". Теперь, если ты скажешь "Москва", коробка сразу даст тебе "Привет".
В программировании такая коробка называется словарь (или хеш-таблица). В Go она называется map.
Словарь хранит пары ключ → значение. Ключи должны быть уникальными (не может быть двух одинаковых ключей), а значения могут повторяться.
Основной синтаксис
В Go словарь создается так:
// Создаем пустой словарь
var myMap map[string]string
myMap = make(map[string]string)
// Или сразу с данными
greetings := map[string]string{
"Россия": "Привет",
"Англия": "Hello",
"Франция": "Bonjour",
}
Здесь string (первый) — тип ключа, string (второй) — тип значения.
Как работать со словарем
Давай разберем основные действия на примере приветствий:
package main
import "fmt"
func main() {
// Создаем словарь
greetings := map[string]string{
"Россия": "Привет",
"Англия": "Hello",
"Франция": "Bonjour",
}
// Добавляем новую запись
greetings["Германия"] = "Hallo"
// Получаем значение по ключу
fmt.Println("В России говорят:", greetings["Россия"])
// Проверяем, есть ли ключ в словаре
value, exists := greetings["Италия"]
if exists {
fmt.Println("В Италии говорят:", value)
} else {
fmt.Println("Италии нет в словаре")
}
// Удаляем запись
delete(greetings, "Франция")
// Выводим все записи
fmt.Println("Все приветствия:")
for country, greeting := range greetings {
fmt.Println(country, "→", greeting)
}
}
Разбор типичных задач
Задача 1: Телефонный справочник
Нужно найти номер телефона по имени человека.
package main
import "fmt"
func main() {
// Словарь: имя → номер телефона
phonebook := map[string]string{
"Анна": "+7-999-123-45-67",
"Иван": "+7-999-765-43-21",
"Мария": "+7-999-555-55-55",
}
var name string
fmt.Print("Введите имя: ")
fmt.Scan(&name)
// Ищем номер
number, found := phonebook[name]
if found {
fmt.Println("Номер телефона:", number)
} else {
fmt.Println("Контакта с таким именем нет")
}
}
Задача 2: Книжная карточка (список дел на неделю)
Храним для каждого дня недели список дел.
package main
import "fmt"
func main() {
// Словарь: день недели → список дел
tasks := map[string][]string{
"Понедельник": {"Купить продукты", "Сходить в банк"},
"Вторник": {"Позвонить другу"},
"Среда": {"Убраться в комнате", "Почитать книгу"},
}
// Добавляем новое дело во вторник
tasks["Вторник"] = append(tasks["Вторник"], "Сделать уроки")
// Выводим все дела на неделю
fmt.Println("План на неделю:")
for day, dayTasks := range tasks {
fmt.Println(day + ":")
for _, task := range dayTasks {
fmt.Println(" -", task)
}
}
}
Задача 3: Удаление контакта (цифровой блокнот)
Удаляем контакт, который больше не нужен.
package main
import "fmt"
func main() {
contacts := map[string]string{
"Олег": "+7-111-222-33-44",
"Настя": "+7-555-666-77-88",
"Дима": "+7-999-000-11-22",
}
fmt.Println("Текущие контакты:")
for name, phone := range contacts {
fmt.Println(name, ":", phone)
}
var nameToDelete string
fmt.Print("Введите имя для удаления: ")
fmt.Scan(&nameToDelete)
// Удаляем контакт
delete(contacts, nameToDelete)
fmt.Println("После удаления:")
for name, phone := range contacts {
fmt.Println(name, ":", phone)
}
}
Задача 4: Ключи словаря (список товаров)
Выводим все названия товаров из словаря.
package main
import "fmt"
func main() {
// Словарь: название товара → цена
products := map[string]float64{
"Хлеб": 45.50,
"Молоко": 89.90,
"Яблоки": 120.00,
"Сыр": 350.00,
}
fmt.Println("Доступные товары:")
for product := range products {
// Используем только ключи
fmt.Println("-", product)
}
// Можно получить все ключи отдельно
var productList []string
for product := range products {
productList = append(productList, product)
}
fmt.Println("\nСписок товаров:", productList)
}
Частые ошибки новичков
- Обращение к несуществующему ключу — Go не выдаст ошибку, но вернет пустое значение (0 для чисел, "" для строк). Всегда проверяй через
value, exists := map[key]. - Попытка записать в nil-словарь — если не вызвать
make(), словарь будет пустым (nil) и запись вызовет панику. Всегда создавай черезmake()или сразу с данными. - Порядок элементов — в Go словарь не гарантирует порядок ключей при обходе. Если нужен порядок, сохраняй ключи в отдельный срез и сортируй его.
Итоговый пример: Словарь для путешественника
Объединим все, что мы узнали:
package main
import "fmt"
func main() {
// Создаем словарь приветствий
dictionary := map[string]string{
"Россия": "Здравствуйте",
"Англия": "Hello",
"Испания": "Hola",
"Япония": "Konnichiwa",
}
fmt.Println("Мой словарь путешественника:")
for country, greeting := range dictionary {
fmt.Printf("%s: %s\n", country, greeting)
}
// Добавляем новую страну
dictionary["Италия"] = "Ciao"
// Ищем приветствие
var searchCountry string
fmt.Print("\nВведите страну для поиска: ")
fmt.Scan(&searchCountry)
if greeting, exists := dictionary[searchCountry]; exists {
fmt.Printf("В %s говорят: %s\n", searchCountry, greeting)
} else {
fmt.Println("Извините, этой страны нет в словаре")
}
// Удаляем страну
var deleteCountry string
fmt.Print("Введите страну для удаления: ")
fmt.Scan(&deleteCountry)
delete(dictionary, deleteCountry)
fmt.Println("\nОбновленный словарь:")
for country, greeting := range dictionary {
fmt.Printf("%s: %s\n", country, greeting)
}
fmt.Printf("\nВсего стран в словаре: %d\n", len(dictionary))
}
Важно! Словари в Go — это мощный инструмент для хранения данных, когда нужно быстро найти значение по ключу. Они работают очень быстро даже с тысячами записей. Помни: ключи должны быть уникальными, а порядок при обходе не гарантируется!