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

Что такое слайс и чем он отличается от массива в Go?

2.0 Middle🔥 152 комментариев
#Основы Go

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

🐱
deepseek-v3.2PrepBro AI7 апр. 2026 г.(ред.)

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

Разница между массивом и слайсом в Go

В языке Go массив и слайс (slice) являются фундаментальными типами данных для работы с последовательностями элементов, но они имеют ключевые различия в своей семантике, поведении и использовании. Понимание этих различий критически важно для эффективного программирования в Go.

Массив: статическая структура данных

Массив в Go — это фиксированная по размеру коллекция элементов одного типа. Длина массива является частью его типа и определяется при компиляции. Она не может быть изменена после создания.

// Массив из 5 целых чисел. Тип: [5]int
var arr [5]int = [5]int{1, 2, 3, 4, 5}

// Попытка изменить размер приведет к ошибке компиляции
// arr = [6]int{1,2,3,4,5,6} // Ошибка: нельзя присвоить [6]int переменной типа [5]int

Ключевые характеристики массива:

  • Фиксированный размер: Длина задается в момент объявления ([N]T).
  • Является значением: При передаче в функцию или присваивании копируется весь массив (все его элементы). Это может быть неэффективно для больших массивов.
  • Сравниваемость: Массивы одного типа и длины можно сравнивать оператором ==.
func processArray(a [3]int) {
    // Здесь работает с локальной копией массива
    a[0] = 100
}

func main() {
    myArray := [3]int{1, 2, 3}
    processArray(myArray)
    fmt.Println(myArray) // Вывод: [1 2 3] (оригинал не изменен)
}

Слайс: динамическая "проекция" на массив

Слайс — это гибкая, динамическая абстракция, предоставляющая "окно" или "проекцию" на участок памяти (обычно базового массива). Он состоит из трех компонентов:

  1. Pointer (ptr): указатель на первый элемент доступного участка в базовом массиве.
  2. Length (len): текущее количество элементов в слайсе.
  3. Capacity (cap): максимальное количество элементов, которые слайс может вместить без перераспределения памяти (размер базового массива от указателя до конца).
// Создание слайса. Тип: []int
mySlice := []int{1, 2, 3, 4, 5} // Слайс с len=5, cap=5

// Слайс можно динамически расширять с помощью append
mySlice = append(mySlice, 6) // len=6, cap может увеличиться (например, до 10)

Ключевые характеристики слайса:

  • Динамический размер: Длина (len) может меняться (обычно через append), хотя емкость (cap) имеет ограничение.
  • Является ссылочным типом: Слайс сам по себе является структурой (значением), содержащей указатель. При передаче в функцию копируется эта структура (указатель, len, cap), но не базовый массив. Поэтому изменения элементов внутри слайса видны в оригинале.
  • Не сравниваемый: Слайсы нельзя сравнивать оператором == (кроме сравнения с nil).
func processSlice(s []int) {
    // Здесь работает с копией структуры слайса, но указатель ссылается на тот же базовый массив
    s[0] = 100
}

func main() {
    mySlice := []int{1, 2, 3}
    processSlice(mySlice)
    fmt.Println(mySlice) // Вывод: [100 2 3] (оригинал изменен!)
}

Основные различия в таблице

ХарактеристикаМассивСлайс
РазмерФиксированный, часть типа.Динамический, может расти (до емкости cap).
ПередачаКопируется целиком (значение).Копируется структура (ссылка на базовый массив).
СравнениеПоддерживается (==).Не поддерживается (кроме nil).
Тип[N]T (например, [5]int).[]T (например, []int).
Созданиеvar arr [3]int или arr := [3]int{1,2,3}.slice := []int{1,2,3} или через make.
ПроизводительностьКопирование может быть дорогим.Передача легкая, но может быть аллокация при append.

Практические примеры и важные нюансы

Создание слайса с помощью make

Функция make позволяет создать слайс с заданной начальной длиной и емкостью, выделяя для него базовый массив.

// Создает слайс длиной 3 и емкостью 5. Базовый массив из 5 элементов готов.
slice := make([]int, 3, 5)
fmt.Println(len(slice), cap(slice)) // 3, 5

Ресайзинг и append

Функция append добавляет элементы. Если емкость (cap) недостаточна, Go автоматически создает новый базовый массив большего размера, копирует в него старые элементы и добавляет новые. После этого слайс ссылается на новый массив.

slice := []int{1, 2} // len=2, cap=2
slice = append(slice, 3, 4, 5) // Требуется больше cap=2
// Go аллоцирует новый массив (например, cap=4 или 6), копирует [1,2], добавляет [3,4,5].
// Старый базовый массив может быть освобожден GC.

"Разрезание" (slicing) и опасность побочных эффектов

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

original := []int{1, 2, 3, 4, 5}
view := original[1:4] // view = [2,3,4], len=3, cap=4 (от 2 до конца original)
view[0] = 99
fmt.Println(original) // [1, 99, 3, 4, 5] ! Изменение в view повлияло на original

Выводы для разработчика:

  • Используйте массивы для статических коллекций с известным небольшим размером, когда важна предсказуемость памяти и сравнение.
  • Слайсы — это основной инструмент для работы с динамическими списками данных в Go. Они эффективны при передаче, но требуют понимания механизма емкости (cap) и поведения функции append (потенциальные аллокации). Особую осторожность следует проявлять при "разрезании", помня о общей базовой памяти.
Что такое слайс и чем он отличается от массива в Go? | PrepBro