Slices in Go are small, struct-like data structures, pointing to a backing array that actually holds the elements of the slice. Slice headers can be modeled with the type reflect.SliceHeader
:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
Quoting from the package doc of fmt
, the verb %p
:
Printing:
The Verbs:
Slice:
%p address of 0th element in base 16 notation, with leading 0x
Pointer:
%p base 16 notation, with leading 0x
The %b, %d, %o, %x and %X verbs also work with pointers,
formatting the value exactly as if it were an integer.
So indeed, passing a slice value for the %p
verb prints the address of the 0th element, which is the 0th element of the backing array, and when you pass &slice
for %p
, that will print the address of the slice header (because &slice
is already a pointer value).
To verify, also print explicitly the address of the 0th element:
fmt.Printf("address of slice %p \n", slice)
fmt.Printf("address of slice %p \n", &slice)
fmt.Println(&slice[0])
Output will be (try it on the Go Playground):
address of slice 0x170460
address of slice 0x17d0b8
0x170460
As you can see, &slice[0]
is the same value as %p
for slice
.
Now let's modify the example to use our own backing array:
var arr = [4]int{1, 2, 3, 4}
var slice = arr[:]
So this way we can also print the address of the 0th element of the backing array:
fmt.Printf("address of slice %p \n", slice)
fmt.Printf("address of slice %p \n", &slice)
fmt.Println(&slice[0])
fmt.Printf("Array 0th: %p", &arr[0])
Output (try it on the Go Playground):
address of slice 0x170460
address of slice 0x183e78
0x170460
Array 0th: 0x170460
And yes, the address of the 0th element of the backing array is indeed the same as the address of the 0th element of the slice, which is the same value printed for slice
when passed for the %p
verb.