Коллекции данных: Массивы, Срезы и Карты

Эта глава — одна из самых важных. В Go коллекции данных (массивы, срезы и карты) используются повсеместно. Если массивы в Go встречаются редко, то срезы (slices) — это «хлеб и соль» любого Go-разработчика.

В этой главе мы изучим, как группировать данные в Go. Мы рассмотрим три основных типа коллекций: массивы (фиксированный размер), срезы (динамический размер) и карты (пары ключ-значение).

Массивы (Arrays)

Массив — это нумерованная последовательность элементов одного типа с фиксированной длиной. В Go длина является частью типа массива. Это значит, что [5]int и [10]int — это абсолютно разные типы данных.

var x [5]int
x[4] = 100
fmt.Println(x) // Выведет [0 0 0 0 100]

  • Индексация начинается с 0.
  • Массивы редко используются в Go напрямую, так как их размер нельзя изменить. Чаще они служат фундаментом для срезов.

Срезы (Slices)

Срез — это сегмент массива. В отличие от массивов, срезы могут изменять свою длину. Срез состоит из трех компонентов: указатель на массив, длина (length) и емкость (capacity).

Создание среза

// С помощью функции make: тип, длина, емкость (опционально)
x := make([]float64, 5, 10) 

Здесь 5 — текущая длина (доступные элементы), а 10 — емкость (сколько элементов срез может вместить без выделения новой памяти).

Выражение [low : high]

Вы можете «отрезать» часть от массива или другого среза:

arr := [5]int{1, 2, 3, 4, 5}
slice := arr[1:4] // Элементы с индексами 1, 2, 3 -> [2, 3, 4]

Функции append и copy

append — добавляет элементы в конец среза. Если места в текущей емкости не хватает, Go создаст новый массив большего размера автоматически.

slice := []int{1, 2, 3}
slice = append(slice, 4, 5) // [1, 2, 3, 4, 5]

[!TIP] Пакет slices В современном Go (начиная с 1.21) есть стандартный пакет slices для удобной работы (сортировка, поиск, реверс). Например: slices.Sort(slice).


Карты (Maps)

Карта — это неупорядоченная коллекция пар ключ-значение. В других языках их называют словарями (Python) или хэш-таблицами (Java).

Инициализация

Важно: Карта должна быть инициализирована через make, иначе при попытке записи программа “упадет” (panic).

elements := make(map[string]string)
elements["H"] = "Hydrogen"
fmt.Println(elements["H"])

Проверка существования (Comma ok idiom)

Если ключа в карте нет, Go вернет “нулевое значение” (например, пустую строку). Чтобы понять, был ли ключ на самом деле, используйте второй результат:

name, ok := elements["Un"]
if ok {
    fmt.Println(name)
} else {
    fmt.Println("Элемент не найден")
}

Удаление

Для удаления используется встроенная функция delete(map, key).


Итоговый пример: Сложные структуры

Карты могут содержать другие карты или срезы:

func main() {
    // Карта, где ключ - строка, а значение - другая карта
    elements := map[string]map[string]string{
        "H": {"name": "Hydrogen", "state": "gas"},
        "Li": {"name": "Lithium", "state": "solid"},
    }

    if el, ok := elements["Li"]; ok {
        fmt.Printf("Имя: %s, Состояние: %s\n", el["name"], el["state"])
    }
}


Задачи

  • Доступ: Как получить доступ к 4-му элементу среза s?
  • Длина и емкость: Чему равны len и cap у среза make([]int, 5, 15)?
  • Срезы: Дан массив x := [6]string{"a","b","c","d","e","f"}. Что выведет fmt.Println(x[2:5])?
  • Алгоритм: Напишите программу, которая находит минимальное число в срезе: ```go x := []int{48, 96, 86, 68, 57, 82, 63, 70, 37, 34, 83, 27, 19, 97, 9, 17}

```

  • Карты: Напишите программу, которая считает количество повторений каждого слова в строке (подсказка: используйте strings.Fields).

Полезные ссылки

  1. Go Blog: Arrays, slices (and strings) — обязательное чтение для понимания механики срезов.
  2. Go by Example: Slices и Maps.
  3. Пакет slices (Go 1.21+) — современные функции для работы со срезами.