Срезы в Go - это небольшие структурные структуры данных, указывающие на резервный массив, который фактически содержит элементы среза. Заголовки срезов можно моделировать с помощью типа reflect.SliceHeader
:
type SliceHeader struct {
Data uintptr
Len int
Cap int
}
Цитирование из пакета документов fmt
, глагол %p
:
Печать:
Глаголы:
Slice:
%p address of 0th element in base 16 notation, with leading 0x
Указатель:
%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.
Таким образом, при передаче значения среза для глагола %p
печатается адрес 0-го элемента, который является 0-м элементом массива поддержки, и когда вы передаете &slice
для %p
, это будет печатать адрес заголовка слайса (поскольку &slice
уже является значением указателя).
Для проверки также явно напечатайте адрес 0-го элемента:
fmt.Printf("address of slice %p \n", slice)
fmt.Printf("address of slice %p \n", &slice)
fmt.Println(&slice[0])
Вывод будет (попробуйте на Go Playground ):
address of slice 0x170460
address of slice 0x17d0b8
0x170460
Как видите, &slice[0]
- это то же значение, что и %p
для slice
.
Теперь давайте изменим пример для использования нашего собственного резервного массива:
var arr = [4]int{1, 2, 3, 4}
var slice = arr[:]
Таким образом, мы также можем напечатать адрес 0-го элемента массива поддержки:
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])
Вывод (попробуйте на Go Playground ):
address of slice 0x170460
address of slice 0x183e78
0x170460
Array 0th: 0x170460
И да, адрес 0-го элемента массива резервирования действительно совпадает с адресом 0-го элемента среза, что соответствует значению, напечатанному для slice
при передаче для глагола %p
.