我如何(简洁地)从Go中的切片中删除第一个元素?

时间:2014-05-08 02:48:25

标签: go queue

我在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 个答案:

答案 0 :(得分:28)

你试过这些吗?

从队列中弹出

x, a = a[0], a[1:]

从堆栈弹出

x, a = a[len(a)-1], a[:len(a)-1]

a = append(a, x)

来自:https://code.google.com/p/go-wiki/wiki/SliceTricks

答案 1 :(得分:4)

如果你想要一个环形缓冲区或FIFO结构,那么在@Everton的答案中使用切片将导致垃圾收集问题,因为底层数组可能会无限增长。

如果你不介意有限的大小,最简单的方法就是使用一个对并发访问也安全的通道。这是一个常见的成语,你通常不会在下面的类型中包装它。

例如(Playground

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())

}