Приоритетные очереди перехода — назначение вложенного среза

#go

#Вперед

Вопрос:

Я читаю приоритетные очереди в стандартной библиотеке Go здесь, и я смотрю на этот код

 func (pq *PriorityQueue) Pop() interface{} {
    old := *pq
    n := len(old)
    item := old[n-1]
    old[n-1] = nil  // avoid memory leak
    item.index = -1 // for safety
    *pq = old[0 : n-1]
    return item
}
 

Я несколько обеспокоен этим методом извлечения элементов из очереди приоритетов.. Я знаю, что PriorityQueue тип — это фрагмент указателей в этом примере, и что фрагмент является ссылочным типом, поэтому old := *pq он только присваивает ссылку на фрагмент и фактически ничего не копирует, но что делает строка *pq = old[0 : n-1] ? Создает ли он другой фрагмент или просто копирует ссылку на старый фрагмент с индексами начала и конца, установленными на 0 и n-1 ?

Я хотел бы использовать этот класс для приоритетной очереди с потенциально большим количеством элементов, и я хотел бы избежать ненужных копий.

Комментарии:

1. Рекомендуемое чтение, которое должно ответить на ваш вопрос: go.dev/blog/slices-intro

2. В Go нет ссылок, как и классов. Если вас беспокоит производительность, вы должны измерить.

Ответ №1:

old := *pq создает копию всего, на что pq указывает.

Копирование фрагмента создает поверхностную копию — копия поддерживается тем же массивом, что и исходный фрагмент.

*pq = old[0 : n-1] создает новый фрагмент, который на 1 элемент короче и поддерживается тем же массивом.

Копирование фрагмента обходится дешево, копирование резервного массива обходится дорого.

Обязательное чтение при работе с срезами: срезы перехода: использование и внутренние компоненты