Нарезка указателя фрагмента, переданного в качестве аргумента
У меня есть следующий код:
func main() {
var buf []byte{1, 2, 3, 4, 5}
buf = buf[2:]
fmt.Println(buf)
panic(1)
}
Однако я хочу передать указатель на buf
срезать байт для другой функции и нарезать ее там, так что-то вроде:
func main() {
var buf []byte{1, 2, 3, 4, 5}
sliceArr(&buf, 2)
fmt.Println(buf)
panic(1)
}
func sliceArr(buf *[]byte, i int) {
*buf = *buf[i:]
}
Это дает мне ошибку, что я не могу использовать тип []byte
как тип *[]byte
в аргументе sliceArr()
функция, и что я не могу нарезать тип *[]byte
, В чем дело? Разве фрагменты не передаются по ссылке по умолчанию? Я пытался сделать это без указателя, но это не работает - массив копируется. Как я могу это сделать?
1 ответ
Ошибка cannot use type []byte as type *[]byte in argument to sliceArr()
исходит из опечатки, которую вы не опубликовали (вы пытались передать фрагмент, а не указатель на фрагмент sliceArr()
).
Что касается другой ошибки (cannot slice type *[]byte
), вам просто нужно использовать скобки для группировки разыменования указателя:
*buf = (*buf)[i:]
И вы случайно пропустили =
знак из объявления переменной. Кроме этого, все работает так, как вы написали:
func main() {
var buf = []byte{1, 2, 3, 4, 5}
sliceArr(&buf, 2)
fmt.Println(buf)
}
func sliceArr(buf *[]byte, i int) {
*buf = (*buf)[i:]
}
Вывод (попробуйте на Go Playground):
[3 4 5]
Замечания:
Обратите внимание, что в спецификации говорится, что если p
это указатель на массив, p[low:high]
это сокращение для (*p)[low:high]
то есть указатель автоматически разыменовывается для вас. Это не происходит автоматически, если p
указатель на срез, p[low:high]
неверно, так как вы не можете нарезать указатель. Таким образом, вы должны разыменовать указатель вручную в случае указателей на фрагменты.
Причиной этого отклонения является то, что указатель на фрагмент очень редок, поскольку фрагменты уже являются "просто" дескрипторами (для непрерывной части базового массива), а фрагменты передаются без указателя большую часть времени, поэтому, если в редких В случае (как этот) вам нужно передать указатель, вы должны четко указать, как его обработать. Массивы с другой стороны представляют все элементы; присваивание или передача массивов копирует все значения, поэтому гораздо чаще использовать указатели на массивы (чем указатели на срезы) - поэтому оправдано иметь больше языковой поддержки для работы с указателями массивов.
Также обратите внимание, что ваша задача может быть достигнута, требуя только (не указатель) срез в качестве типа параметра и возвращая новое значение среза - который, конечно, должен быть назначен вызывающей стороне (хорошим примером этого является встроенный append()
функция).
Заметка 2:
Если тип параметра представляет собой срез (а не указатель на срез), и вы передаете срез, базовый массив не копируется, только заголовок среза. Но в этом случае, если вы срезаете аргумент (который является копией заголовка среза) и присваиваете новый срез (заголовок среза) этому аргументу, вы просто меняете значение параметра (локальной переменной) и не оригинальное значение (переменная), которое было передано, поэтому оно не будет работать.
Прочитайте следующие сообщения в блоге для более подробной информации о ломтиках: