2016-06-24 7 views
0

У меня есть следующий код:нарезка указатель среза, переданного в качестве аргумента

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. Что не так? Не разрешены ли срезы по ссылке по умолчанию? Я попытался сделать это без указателя, но он не работает - массив копируется. Как я могу это сделать?

ответ

7

Ошибка 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:] 
} 

Output (попробовать его на Go Playground):

[3 4 5] 

Примечание:

Обратите внимание, что specification states, что если p является указатель на массив , p[low:high] является сокращением для (*p)[low:high], то есть указателем являются разыменованные автоматы для вас. Это не происходит автоматически, если p является указателем на фрагмент, p[low:high] недействителен, так как вы не можете нарезать указатель. Таким образом, вы должны разыменовать указатель вручную в случае указателей на срезы.

Причина этого отклонения заключается в том, что указатель на срез очень редок, поскольку срезы уже являются «справедливыми» дескрипторами (к смежной части базового массива), а срезы передаются без указателя большую часть времени, поэтому если в редком случае (например, этот) вам нужно передать указатель, вам нужно четко указать его обработку. Массивы, с другой стороны, представляют все элементы; присваивание или передача массивов копирует все значения, поэтому гораздо чаще используется указатель на массивы (чем указатели на срезы) - поэтому вполне оправданно иметь больше поддержки языка для работы с указателями массива.

Также обратите внимание, что ваша задача может быть достигнута за счет использования только фрагмента (не указателя) в качестве типа параметра и возврата нового значения среза, который, конечно, должен быть назначен у вызывающего (хорошим примером для этого является встроенный append() функция).

Примечание # 2:

Если тип параметра является срез (а не указатель на срезе), и вы передаете кусочек, основной массив не копируется, только заголовок секции.Но в этом случае, если вы разрезаете аргумент (который является копией заголовка среза) и вы назначаете новый срез (заголовок среза) на аргумент, вы просто изменяете значение параметра (локальную переменную) и а не исходное значение (переменная), которое было передано, поэтому он не будет работать.

Прочитайте следующие сообщения пользователя для более подробной информации по кусочкам:

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'

Смежные вопросы