🐹 Go

Словари и хеш-таблицы в 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 — это мощный инструмент для хранения данных, когда нужно быстро найти значение по ключу. Они работают очень быстро даже с тысячами записей. Помни: ключи должны быть уникальными, а порядок при обходе не гарантируется!