Golang tricks: работа слайсов
Что будет выводить функция fmt.Println(slice) в каждом случае и почему:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
func main() { slice := make([]int, 3, 4) prikol(slice) fmt.Println(slice) // вопрос: Изменился ли слайс? prikol(slice) fmt.Println(slice) // вопрос: Изменился ли слайс? prikol(slice[:1]) fmt.Println(slice) // вопрос: Изменился ли слайс? } func prikol(slice []int) { slice = append(slice, 1) } |
Разберем, что происходит на каждом этапе этого кода.
Что делает make([]int, 3, 4)
Эта строка создает слайс slice
с:
- длиной 3 (
len(slice) = 3
), - вместимостью 4 (
cap(slice) = 4
), - инициализированный значениями
[0, 0, 0]
(по умолчанию дляint
).
Детали функции prikol
Функция prikol
:
- принимает слайс в качестве аргумента,
- делает
append
с добавлением числа1
в конец слайса.
Здесь важно понимать, что append
работает по-разному в зависимости от вместимости слайса:
- Если текущая вместимость слайса позволяет вместить новый элемент,
append
добавит элемент в конец текущего массива, на который указывает слайс, и вернет тот же массив. - Если вместимость исчерпана,
append
создаст новый массив с удвоенной вместимостью, скопирует данные из старого массива в новый и вернет новый массив.
Но! Поскольку append
возвращает новый слайс, то для того чтобы результат сохранился, его нужно присвоить обратно. В функции prikol
этого не делается, что играет решающую роль.
Анализ по строкам
- Первая строка
prikol(slice)
В этой строке функцияprikol
получает копию слайсаslice
:append
добавляет1
, и полученный слайс[0, 0, 0, 1]
создается с вместимостью 4.- Но
slice = append(slice, 1)
присваивается только внутриprikol
, без влияния на исходныйslice
вmain
.
В итоге внешний
slice
не меняется и остается[0, 0, 0]
.12fmt.Println(slice) // Выводит: [0 0 0] - Вторая строка
prikol(slice)
Повторный вызовprikol(slice)
снова работает по аналогии с первым:- Внутри
prikol
снова создается новый слайс[0, 0, 0, 1]
, но изменения не передаются обратно вmain
.
Поэтому снова внешний
slice
остается неизменным и равен[0, 0, 0]
.12fmt.Println(slice) // Выводит: [0 0 0] - Внутри
- Третья строка
prikol(slice[:1])
Здесь начинается самое интересное:- В
prikol
передается слайсslice[:1]
, который имеет длину 1 и емкость 4 (так как он «видит» оставшуюся часть массива). - Теперь
append(slice, 1)
добавляет1
в позицию[1]
, и, поскольку это тот же базовый массив, изменение отражается наslice
вmain
.
В результате после третьего вызова
slice
вmain
становится[0, 1, 0]
. - В
Recommended Posts
Golang Sarama: настройка Partitioner
20.03.2024