Коллекции: массивы, срезы и отображения

Разделяемый базовый массив, copy и подсрезы

Содержание курса

make и copy: создание независимой копии среза

Чтобы получить срез с собственным базовым массивом, нужно сначала выделить память — через make([]T, n) — и затем перенести элементы через copy. Ни одно из этих действий само по себе не даёт полного результата: make([]T, n) создаёт срез длины n, заполненный нулевыми значениями типа T — это не nil-срез, а реальный массив из нулей; данные src в нём появятся только после copy. А copy без предварительно выделенного dst просто некуда писать.

package main

import "fmt"

func main() {
    src := []int{10, 20, 30, 40, 50}

    dst := make([]int, len(src)) // срез длины 5, элементы пока все равны 0
    n := copy(dst, src)          // копирует min(len(dst), len(src)) элементов

    fmt.Println("скопировано:", n)   // 5
    fmt.Println("dst:", dst)         // [10 20 30 40 50]

    dst[0] = 999
    fmt.Println("src после изменения dst:", src) // [10 20 30 40 50] — не изменился
}

copy возвращает количество скопированных элементов — это всегда min(len(dst), len(src)). Если dst короче src, скопируется только то, что влезает; остаток src отбрасывается. Если dst длиннее — лишние позиции останутся нулями. Возвращаемое число редко нужно сохранять в переменную, но важно понимать: именно оно говорит, сколько элементов реально перешло.

После copy у dst и src разные базовые массивы. Запись dst[0] = 999 не затрагивает src — что и подтверждает последний fmt.Println.

Одно важное уточнение: сам copy не выделяет память. Если написать var dst []int; copy(dst, src), copy честно скопирует ноль элементов, потому что len(dst) == 0. Память нужно выделить явно через make до вызова copy.

Граница применимости. Для []int — как в примере выше — отдельный базовый массив даёт полную независимость: изменение любого элемента через dst не видно через src и наоборот. Это работает, потому что int копируется как значение. copy всегда копирует элементы именно как значения. Если элементы сами содержат указатели, срезы или map, то скопируется ссылка, а не объект, на который она указывает — оба среза будут разделять вложенные данные. Глубокое копирование таких структур в рамках этого урока не рассматривается.