Александр Гольцман
Функция make в Go
Функция make
в Go используется для создания срезов, карт и каналов. Она позволяет заранее выделить память и настроить структуру данных для работы, что особенно полезно при оптимизации производительности.
В этой статье я покажу, как работает make
, в каких случаях ее стоит использовать и чем она отличается от new
. Также разберем примеры применения этой функции в реальном коде.
Зачем нужна функция make
В Go выделение памяти и управление структурами данных устроено довольно просто. Однако, когда речь идет о срезах, картах и каналах, стандартные подходы не всегда удобны.
Функция make
позволяет:
- Создавать срезы с предопределенной длиной и емкостью.
- Инициализировать карты (map), избегая нулевых значений.
- Создавать каналы с указанным буфером.
Важно понимать, что make
не просто выделяет память, а именно инициализирует структуры, делая их готовыми к использованию.
Использование make для создания срезов
Срезы (slice) в Go — это динамические массивы, которые могут изменять свою длину. С помощью make
можно создать срез нужного размера и задать его емкость:
s := make([]int, 5, 10)
Здесь:
5
— начальная длина среза (сколько элементов сразу доступно).10
— емкость (сколько элементов можно добавить без перераспределения памяти).
Если емкость не указывать, она будет равна длине:
s := make([]int, 5) // Длина 5, емкость тоже 5
Смотрите, как работает изменение длины среза:
s = append(s, 42)
fmt.Println(len(s), cap(s)) // Длина 6, емкость 10
Создание map с помощью make
Карты (map) в Go — это структуры для хранения данных в формате "ключ-значение". make
нужен, чтобы инициализировать карту перед использованием:
m := make(map[string]int)
m["one"] = 1
m["two"] = 2
Без make
карта будет nil
, и любое обращение к ней вызовет ошибку:
var m map[string]int
m["one"] = 1 // Ошибка: panic: assignment to entry in nil map
С помощью make
можно задать начальную емкость (хотя она динамически увеличивается при необходимости):
m := make(map[string]int, 100) // Ожидаем, что будет ~100 элементов
Создание каналов через make
Каналы (channel) используются для передачи данных между горутинами. Без make
они не работают.
Простой пример создания канала:
ch := make(chan int)
Если канал буферизированный, можно указать размер буфера:
ch := make(chan int, 3)
Теперь в канал можно отправить три значения, прежде чем горутина-записывающий заблокируется:
ch <- 1
ch <- 2
ch <- 3
// ch <- 4 // Это вызовет блокировку, так как буфер заполнен
Смотрите, как работает чтение из канала:
fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
fmt.Println(<-ch) // 3
Чем make отличается от new
Go также имеет функцию new
, но она работает иначе.
make
инициализирует объекты (срезы, карты, каналы).new
просто выделяет память, но не инициализирует структуру.
Смотрите, в чем разница:
s1 := make([]int, 5) // Готовый срез
s2 := new([]int) // Указатель на nil-срез
s2
— это *[]int
, и с ним нельзя сразу работать, его нужно дополнительно инициализировать.
Так что в большинстве случаев make
удобнее.
Выводы
Функция make
— это мощный инструмент для создания динамических структур в Go.
- Используйте
make
для срезов, если хотите задать начальную длину и емкость. - Для карт
make
обязателен, иначе карта будетnil
. - Каналы тоже требуют
make
, иначе они не будут работать. - Не путайте
make
иnew
:make
инициализирует объекты,new
просто выделяет память.
Смотрите, какие структуры вам нужны, и используйте make
, когда требуется инициализация.
Карта развития разработчика
Получите полную карту развития разработчика по всем направлениям: frontend, backend, devops, mobile