← Назад к вопросам

Зачем делать массив из слайса в Go?

2.0 Middle🔥 151 комментариев
#Основы Go#Производительность и оптимизация

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Зачем делать массив из слайса в Go?

Это отличный вопрос на собеседовании, потому что правильный ответ показывает глубокое понимание различий между массивами и слайсами в Go.

Различие между массивом и слайсом

В Go это совершенно разные типы данных:

Массив:

var arr [5]int  // массив фиксированной длины 5
arr[0] = 10

Слайс:

var slice []int  // слайс переменной длины
slice = append(slice, 10)

Отличия фундаментальны:

  • Массив имеет фиксированный размер, слайс нет
  • Массив это значимый тип (value type), слайс это ссылочный тип (reference type)
  • Массив полностью копируется при передаче функции, слайс передаёт заголовок

Зачем конвертировать слайс в массив?

1. Передача по значению (Value Semantics)

Массив копируется при передаче, слайс нет. Иногда это важно:

// Слайс — передаётся заголовок (ptr, len, cap)
func modifySlice(s []int) {
    s[0] = 999  // МОДИФИЦИРУЕТ оригинальный слайс!
}

slice := []int{1, 2, 3}
modifySlice(slice)
fmt.Println(slice)  // [999 2 3] — изменился!

// Массив — копируется полностью
func modifyArray(arr [3]int) {
    arr[0] = 999  // НЕ модифицирует оригинальный массив
}

arr := [3]int{1, 2, 3}
modifyArray(arr)
fmt.Println(arr)  // [1 2 3] — не изменился!

Если нужна иммутабельность или защита от непредвиденных изменений, массив лучше.

2. Использование в map ключах

Массивы можно использовать как ключи в map, слайсы нельзя:

// Массив как ключ — работает
var m = make(map[[2]int]string)
m[[2]int{1, 2}] = "key"

// Слайс как ключ — ОШИБКА компиляции
var m2 = make(map[[]int]string)  // slice can only be compared to nil

Это полезно для кешей по координатам, составным ключам и т.д.

// Пример: кеш позиций на доске
var positionCache = make(map[[2]int]bool)
positionCache[[2]int{3, 4}] = true

3. Функции, требующие массив

Некоторые функции требуют ровно определённый размер (например, cryptographic функции):

import "crypto/sha256"

var hash [32]byte = sha256.Sum256(data)
// это возвращает [32]byte, а не []byte

// Если нужен слайс — конвертируем
hashSlice := hash[:]  // слайс всех элементов

4. FFI и взаимодействие с C

При вызове C кода через cgo нужны массивы фиксированного размера:

// unsafe работает с массивами
var buffer [256]byte
C.copy_data((*C.char)(unsafe.Pointer(&buffer[0])))

5. Zero-cost abstraction и оптимизация

Массив с фиксированным размером компилятор может лучше оптимизировать:

// Компилятор знает точный размер и может allocate на стеке
var coordinates [1000000][2]float64
// vs
var coordinates [][2]float64  // слайс требует heap allocation

Практический пример конверсии

// Функция требует [16]byte для UUID
func processUUID(id [16]byte) {
    // работа с массивом
}

// У нас есть слайс
data := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}

// Конвертируем в массив
var arr [16]byte
copy(arr[:], data)  // копируем данные
processUUID(arr)    // передаём массив

Или используя синтаксис слайса:

func processSlice(data [16]byte) {}

// В Go 1.20+ можно использовать... (но это усложнило)
var arr [16]byte
copy(arr[:], sliceData)

Когда использовать массив вместо слайса

СлучайПричинаПример
Map ключСлайсы не hashablecache [[2]int]value
ImmutabilityЗащита от измененийПередача координат
C interopТребует фиксированный размерcgo вызовы
Stack allocationБыстро, нет gc[128]byte буферы
КриптографияТребует точный размер[32]byte хеши

Вывод

Конверсия слайса в массив нужна в специфичных случаях:

  • Когда требуется value semantics
  • Для использования как ключ в map
  • Для FFI и low-level операций
  • Для оптимизации stack allocation

В 99% случаев слайсы удобнее и гибче. Используй массивы только когда есть конкретная причина.

Зачем делать массив из слайса в Go? | PrepBro