Go

What is a slice header, and what really gets passed when you pass a slice to a function?

Question 40MediumGo 1.22 to 1.25

A slice is a small struct of three words, {ptr *T, len int, cap int}. It holds a pointer to a backing array, the number of elements you can see (len), and how many elements exist from ptr to the end of that array (cap). Go passes everything by value, so a function gets a copy of the header. Both headers point at the same backing array.

So the callee can change existing elements and the caller sees it. If the callee changes its own len/cap (with append or reslicing), the caller does not see that, because the caller's header never changed.

func mutate(s []int) {
	s[0] = 99          // visible to caller (shared array)
	s = append(s, 4)   // changes only the local header
}

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

What the interviewer wants to hear: slices are not "reference types" the way Java lists are. They are value headers that point to shared storage. That is why idiomatic APIs return the new slice (s = append(s, x)), and why you pass *[]T only when a function has to resize the caller's slice in place.

More on Arrays, Slices, Maps & Strings

All 37 Arrays, Slices, Maps & Strings questions