Ответ
Ключевое отличие в том, как Go обрабатывает передачу этих типов в функции. В Go всё передаётся по значению, но для массивов и слайсов это приводит к совершенно разному поведению.
Передача массива
При передаче массива в функцию создаётся полная копия всего массива. Любые изменения, сделанные внутри функции, затрагивают только эту копию и не влияют на исходный массив.
- Последствия: Это может быть очень неэффективно с точки зрения производительности и потребления памяти, если массив большой.
func modifyArray(arr [3]int) {
arr[0] = 100 // Изменяется только локальная копия
}
func main() {
originalArray := [3]int{1, 2, 3}
modifyArray(originalArray)
fmt.Println(originalArray) // Вывод: [1 2 3]
}
Передача слайса
Слайс — это легковесная структура-обёртка над массивом, которая состоит из трёх полей:
- Указатель на первый элемент базового массива.
- Длина (length) — количество элементов в слайсе.
- Ёмкость (capacity) — количество элементов от начала слайса до конца базового массива.
Когда вы передаёте слайс в функцию, копируется только эта структура (заголовок слайса), а не весь базовый массив. Поскольку копия заголовка содержит тот же указатель на тот же базовый массив, изменения элементов слайса внутри функции будут видны снаружи.
func modifySlice(slice []int) {
// Изменяем элемент базового массива, на который указывает слайс
slice[0] = 100
}
func main() {
originalSlice := []int{1, 2, 3}
modifySlice(originalSlice)
fmt.Println(originalSlice) // Вывод: [100 2 3]
}
Важный нюанс с append
Если внутри функции вы используете append
, и это приводит к превышению ёмкости (capacity
) слайса, Go создаст новый базовый массив и скопирует туда старые элементы. Указатель в заголовке слайса внутри функции будет обновлён, но заголовок исходного слайса снаружи останется прежним.
func appendToSlice(slice []int) {
slice = append(slice, 4) // Создаётся новый массив, т.к. capacity исчерпана
}
func main() {
s := make([]int, 3, 3) // len=3, cap=3
appendToSlice(s)
fmt.Println(s) // Вывод: [0 0 0], а не [0 0 0 4]
}
Итог:
- Массив: Передаётся по значению (копируется целиком). Дорого для больших массивов. Изменения внутри функции не видны снаружи.
- Слайс: Передаётся по значению (копируется только заголовок). Эффективно. Изменения элементов внутри функции видны снаружи, так как оба заголовка (оригинал и копия) указывают на один и тот же базовый массив.