Как я (кратко) удаляю первый элемент из среза в Go?

Я создал простую очередь в Go. Он использует внутренний срез для отслеживания его элементов. Элементы помещаются в очередь, добавляя к срезу. Я хотел бы реализовать .Pop(), удалив первый элемент в elements.

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

type Queue struct {
    elements []interface{}
}

func (queue *Queue) Push(element interface{}) {
    queue.elements = append(queue.elements, element)
}

func (queue *Queue) Pop() interface{} {
    element := queue.elements[0]
    if len(queue.elements) > 1 {
        queue.elements = queue.elements[1:]
    } else {
        queue.elements = make([]interface{}, 0)
    }
    return element
}

Обратите внимание, что я хочу, чтобы Queue в панике, если len(queue.elements) == 0. Это не недосмотр, что я не проверяю границы.

Ответ 2

Если вам нужен кольцевой буфер или структура FIFO, то использование среза, как в ответе @Everton, вызовет проблемы с сборкой мусора, поскольку базовый массив может расти бесконечно.

Самый простой способ сделать это в go, если вы не против иметь ограниченный размер, - использовать канал, который также безопасен для одновременного доступа. Это такая распространенная идиома в том, что вы обычно не утруждаете ее упаковкой в виде, подобном приведенному ниже.

Например (детская площадка)

package main

import "fmt"

type Queue struct {
    elements chan interface{}
}

func NewQueue(size int) *Queue {
    return &Queue{
        elements: make(chan interface{}, size),
    }
}

func (queue *Queue) Push(element interface{}) {
    select {
    case queue.elements <- element:
    default:
        panic("Queue full")
    }
}

func (queue *Queue) Pop() interface{} {
    select {
    case e := <-queue.elements:
        return e
    default:
        panic("Queue empty")
    }
    return nil
}

func main() {
    q := NewQueue(128)

    q.Push(1)
    q.Push(2)
    q.Push(3)
    fmt.Printf("Pop %d\n", q.Pop())
    fmt.Printf("Pop %d\n", q.Pop())
    fmt.Printf("Pop %d\n", q.Pop())
    fmt.Printf("Pop %d\n", q.Pop())

}