英文:
How do I (succinctly) remove the first element from a slice in Go?
问题
我已经在Go中构建了一个简单的队列。它使用一个内部切片来跟踪其元素。通过将元素追加到切片中,将元素推入队列。我想通过删除elements
中的第一个元素来实现.Pop()
。在许多其他语言中,"弹出"列表的第一个元素是一行代码,这让我相信我下面的实现方法可能有些冗长和啰嗦。有更好的方法吗?
请注意,如果len(queue.elements) == 0
,我希望Queue
引发panic。我没有检查边界并不是疏忽。
英文:
I've built a simple queue in Go. It uses an internal slice to keep track of its elements. Elements are pushed onto the queue by appending to the slice. I'd like to implement .Pop()
by removing the first element in elements
.
In many other languages, "popping" the first element of a list is a one-liner, which leads me to believe my implementation below is sloppy and verbose. Is there a better way?
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
}
Please note that I wish for the Queue
to panic if len(queue.elements) == 0
. It's not an oversight that I don't check the bounds.
答案1
得分: 260
你试过这些吗?
从队列中弹出元素
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
英文:
Did you try these?
Pop from queue
x, a = a[0], a[1:]
Pop from stack
x, a = a[len(a)-1], a[:len(a)-1]
Push
a = append(a, x)
答案2
得分: 13
如果你想要一个环形缓冲区或FIFO结构,那么像@Everton的答案中使用切片会导致垃圾回收问题,因为底层数组可能会无限增长。
在Go语言中,最简单的方法是使用通道(channel),只要你不介意有限的大小,这也是安全的并发访问。在Go语言中,这是一个非常常见的习惯用法,通常不需要像下面的示例那样将其封装成一个类型。
例如(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())
}
英文:
If you want a ring buffer or FIFO structure then using a slice as in @Everton's answer will cause garbage collection problems as the underlying array may grow indefinitely.
The easiest way to do this in go, provided you don't mind having a limited size, is to use a channel which is also safe for concurrent access. This is such a common idiom in go that you wouldn't usually bother wrapping it in a type like the below.
Eg (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())
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论