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

Какие поля содержит слайс?

1.0 Junior🔥 172 комментариев
#Основы Go

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

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

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

Структура слайса в Go

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

Три основных поля слайса

С точки зрения реализации в runtime Go, слайс содержит следующие поля:

struct Slice {
    ptr *T        // указатель на первый элемент базового массива
    len int       // текущая длина (количество элементов, доступных в слайсе)
    cap int       // ёмкость (максимальное количество элементов, которые могут быть размещены без реаллокации)
}

1. ptr (pointer)

  • Это указатель на первый элемент базового (underlying) массива, в котором фактически хранятся данные слайса.
  • Слайс не содержит данные самостоятельно — он лишь ссылается на часть массива (или весь массив).
  • Именно поэтому несколько слайсов могут ссылаться на один и тот же базовый массив, что приводит к явлению aliasing (перекрытие).

2. len (length)

  • Это текущая длина слайса — количество элементов, которые можно прочитать или записать в пределах слайса.
  • Длина возвращается функцией len() и определяет, сколько элементов доступно slice[0] до slice[len-1].
  • Длина всегда меньше или равна ёмкости.

3. cap (capacity)

  • Это ёмкость слайса — максимальное количество элементов, которые могут быть размещены в базовом массиве без выделения нового массива и копирования данных.
  • Ёмкость возвращается функцией cap() и определяет, до какого индекса можно расширить слайс с помощью операции re-slicing (slice[:cap]).

Пример внутреннего представления

Рассмотрим пример создания слайса:

package main

import (
    "fmt"
    "unsafe"
)

func main() {
    arr := [5]int{1, 2, 3, 4, 5}  // базовый массив
    slice := arr[1:4]             // слайс с элементами 2,3,4

    // Получаем указатель, длину и ёмкость через unsafe (для демонстрации)
    slicePtr := unsafe.Pointer(&slice)
    sliceHeader := (*[3]int)(slicePtr)

    fmt.Printf("ptr (примерный адрес): %v\n", sliceHeader[0])
    fmt.Printf("len: %d\n", sliceHeader[1]) // len(slice) = 3
    fmt.Printf("cap: %d\n", sliceHeader[2]) // cap(slice) = 4 (от arr[1] до конца arr)
}

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

Практические следствия структуры слайса

  1. Передача слайса в функции — передаётся не весь массив данных, а только эта структура (три поля), что очень эффективно.
  2. Изменения элементов — если два слайса ссылаются на один базовый массив, изменение элемента в одном слайсе повлияет на другой.
  3. Операции re-slicing — создание нового слайса из существующего (slice[i:j]) не копирует данные, а лишь создаёт новую обёртку с новыми len и cap, но тем же ptr.
  4. Расширение слайса — если при добавлении через append() ёмкость превышена, выделяется новый базовый массив, ptr изменяется на новый адрес, cap увеличивается (обычно в 2 раза для небольших слайсов).

Это внутреннее представление объясняет, почему слайсы в Go одновременно эффективны (минимум копирования) и требуют внимания при работе (проблемы aliasing, реаллокации).

Какие поля содержит слайс? | PrepBro