У вашому прикладі sliceаргумент Testфункції отримує копію змінної aв області виклику.
Оскільки змінна зрізу містить "дескриптор зрізу", який просто посилається на базовий масив, у вашій Testфункції ви sliceкілька разів поспіль модифікуєте дескриптор зрізу, що міститься у змінній, але це не впливає на абонента та його aзмінну.
Усередині Testфункції перший appendперерозподіляє масив підкладки під sliceзмінною, копіює її оригінальний вміст, додає 100до нього, і це те, що ви спостерігаєте. Після виходу із Test, sliceзмінна виходить за межі області дії, а також (новий) базовий масив, що нарізає посилання. ( Джефф Лі правильно говорить про те, що насправді трапляється не те, тож насправді відбувається оновлена версія; як він правильно стверджує, ця відповідь є правильною, якщо, можливо, трохи стисла.)
Поза Testфункцією виділяється зріз довжиною 7 та місткістю 8, а його 7 елементів заповнені.
Усередині Testфункції перший appendбачить, що ємність зрізу все ще на один елемент більша за його довжину - іншими словами, є місце для додавання ще одного елемента без перерозподілу. Отже, він «з’їдає» той елемент, що залишився, і розміщує 100на ньому, після чого регулює довжину в копії дескриптора зрізу, щоб стати рівною капітатичності зрізу. Це не впливає на дескриптор фрагмента в області дії абонента.
І це те, що ви спостерігаєте. Після виходу з Test, sliceзмінна виходить за межі області дії, а також (новий) базовий масив, що нарізає посилання.
Якщо ви хочете змусити Testсебе вести себе так append, вам доведеться повернути з нього новий зріз - так само, як appendце робить - і вимагати від абонентів, Testщоб використовували його так само, як і вони append:
func Test(slice []int) []int {
slice = append(slice, 100)
fmt.Println(slice)
return slice
}
a = Test(a)
Будь ласка, уважно прочитайте цю статтю, оскільки вона в основному показує вам, як реалізувати appendвручну, після пояснення того, як фрагменти працюють усередині. Тоді прочитайте це .