Зарегистрируйтесь, чтобы продолжить обучение

Передача срезов в функцию Основы Go

Срезы в Go — это лёгкие структуры, содержащие указатель на базовый массив, длину (len) и вместимость (cap). При передаче в функцию срез копируется как структура, но оба среза продолжают указывать на один и тот же массив. Это поведение важно для понимания того, когда изменения внутри функции отражаются на исходных данных, а когда нет.

Передача срезов

При передаче среза в функцию изменения элементов видны снаружи, потому что копируется только структура, а не массив.

func modify(s []int) {
    s[0] = 99
}

func main() {
    nums := []int{1, 2, 3}
    modify(nums)
    fmt.Println(nums) // => [99 2 3]
}

Здесь функция modify() изменила первый элемент, и изменение видно в main().

Вызов append() внутри функции

При использовании append() поведение зависит от вместимости исходного среза:

  • Если append() помещается в существующий массив, изменения видны снаружи.
  • Если append() создаёт новый массив (переполнена cap), изменения не будут видны, если не вернуть новый срез.
func addElement(s []int) {
    s = append(s, 100)
}

func main() {
    nums := []int{1, 2, 3}
    addElement(nums)
    // изменений нет
    fmt.Println(nums) // => [1 2 3]
}

Чтобы изменения сохранились, возвращаем срез из функции:

func addElement(s []int) []int {
    return append(s, 100)
}

func main() {
    nums := []int{1, 2, 3}
    nums = addElement(nums)
    fmt.Println(nums) // => [1 2 3 100]
}

Возврат срезов

Возвращение срезов из функций безопасно: копируется только структура, а массив остаётся в памяти столько, сколько нужен.

func newSlice() []int {
    s := []int{1, 2, 3}
    return s
}

func main() {
    data := newSlice()
    fmt.Println(data) // => [1 2 3]
}

Под-срезы и утечки памяти

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

data := make([]int, 10000)
part := data[:10] // удерживает весь массив из 10000 элементов

Чтобы освободить неиспользуемую память, можно сделать копию:


import "slices"

data := make([]int, 10000)
part := slices.Clone(data[:10])

Вывод

  • Срезы передаются по значению, но содержат указатель на общий массив.
  • Изменения элементов внутри функции видны снаружи.
  • При использовании append() новый срез может указывать на другой массив — его нужно возвращать.
  • Возврат срезов безопасен, но под-срезы больших массивов могут удерживать память, которую стоит освобождать через копирование.
  • Чтобы избежать утечки памяти, скопируйте нужную часть среза, например через slices.Clone().

Дополнительные материалы

  1. Slice types

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff