Python 的 list.pop() 方法的 Go 习惯用法是什么?

问题描述 投票:0回答:7

在Python中,我有以下内容:

i = series.index(s) # standard Python list.index() function
tmp = series.pop(i)
blah = f(tmp)
series.append(tmp)

在将其转换为 Go 时,我正在寻找一种类似的方法,通过索引从切片中检索项目,用它做一些事情,然后将原始项目放在切片的末尾。

这里,我得到了以下结果:

i = Index(series, s) // my custom index function...
tmp, series = series[i], series[i+1:]
blah := f(tmp)
series = append(series, tmp)

但这在列表末尾失败了:

panic: runtime error: slice bounds out of range

我如何将这个

slice.pop()
惯用地翻译成 Go?

list go slice
7个回答
21
投票

链接文档中的“剪切”技巧可以满足您的需求:

xs := []int{1, 2, 3, 4, 5}

i := 0 // Any valid index, however you happen to get it.
x := xs[i]
xs = append(xs[:i], xs[i+1:]...)
// Now "x" is the ith element and "xs" has the ith element removed.

请注意,如果您尝试从获取和剪切操作中创建一行,您将得到意想不到的结果,因为在计算其他表达式之前调用函数的多个赋值的棘手行为

i := 0
x, xs := xs[i], append(xs[:i], xs[i+1:]...)
// XXX: x=2, xs=[]int{2, 3, 4, 5}

您可以通过将元素访问操作包装在任何函数调用中来解决此问题,例如恒等函数:

i := 0
id := func(z int) { return z }
x, xs := id(xs[i]), append(xs[:i], xs[i+1:]...)
// OK: x=1, xs=[]int{2, 3, 4, 5}

但是,此时使用单独的分配可能会更清楚。

为了完整起见,“cut”函数及其用法可能如下所示:

func cut(i int, xs []int) (int, []int) {
  y := xs[i]
  ys := append(xs[:i], xs[i+1:]...)
  return y, ys
}

t, series := cut(i, series)
f(t)
series = append(series, t)

9
投票

如果你想编写一个以类似于 python 的方式执行 pop() 的函数,那么你必须传入一个指向该对象的指针,以便可以修改该对象,因为 pop 既返回值又更改列表

func pop(alist *[]int) int {
   f:=len(*alist)
   rv:=(*alist)[f-1]
   *alist=(*alist)[:f-1]
   return rv
}

func main() {
n:=[]int{1,2,3,4,5}
fmt.Println(n)
last:=pop(&n)
fmt.Println("last is",last)
fmt.Printf("list of n is now %v\n", n)

3
投票

您可以声明

type intSlice []int
,并且可以使用该指针接收器声明方法
pop()
func (l *intSlice) pop() int
。然后你可以在
.pop()
对象的实例上调用
intSlice
。这在风格上变得更类似于 Python。

package main

import (
    "fmt"
)

type intSlice []int

func (l *intSlice) pop() int {
    length := len(*l)
    lastEle := (*l)[length-1]
    *l = (*l)[:length-1]
    return lastEle
}

func main() {

    mySlice := intSlice{1, 2, 3, 4, 5, 6}

    popped := mySlice.pop()

    fmt.Println(popped)
    fmt.Println(mySlice)

    popped = mySlice.pop()

    fmt.Println(popped)
    fmt.Println(mySlice)

}

结果:

6
[1 2 3 4 5]
5
[1 2 3 4]

去游乐场


2
投票

另一种选择是创建一个函数,该函数接受一个指向 int 切片的指针,该函数修改参数以删除最后一个值并返回它:

func pop(xs *[]int) int {
  x := (*xs)[len(*xs)-1]   // Store the last value to return.
  *xs = (*xs)[:len(*xs)-1] // Remove the last value from the slice.
  return x
}

例如(Go Playground)

xs := []int{1, 2, 3} // => xs=[1, 2, 3]
x := pop(&xs)        // => xs=[1, 2],   x=3

1
投票

我不确定是否有“pop()”的直接等价物......但你可以这样做:

围棋之旅

可以使用内置的make函数创建切片;就是这样 您创建动态大小的数组。

make 函数分配一个归零数组并返回一个切片 引用该数组:

a := make([]int, 5)  // len(a)=5

要指定容量,请将第三个参数传递给 make:

b := make([]int, 0, 5) // len(b)=0, cap(b)=5

b = b[:cap(b)] // len(b)=5, cap(b)=5

b = b[1:]      // len(b)=4, cap(b)=4

另请参阅:


1
投票

我会做一些类似于paulsm4建议的事情:

package main

import (
    "fmt"
)

func main() {
    a := []int{1,2,3,4,5}
    i,b := pop(a)
    fmt.Println(i,b) // 5 [1 2 3 4]
}

func pop(a []int) (int,[]int) {
    return a[len(a)-1],a[:len(a)-1]
}

去游乐场


0
投票

这是一个使用指针就地修改列表的版本,同时支持可选的“index”参数,如Python pop。它使用泛型来支持切片中任何类型的元素,因此您可能需要针对 golang 进行修改 <1.18

func pop[T comparable](xs *[]T, index int) T {
if index < 0 {
    index = len(*xs) + index
}
x := (*xs)[index] // Store the last value to return.
if index < len(*xs)-1 {
    *xs = append((*xs)[:index], (*xs)[index+1:]...)
} else {
    *xs = (*xs)[:index]
}
return x

}

© www.soinside.com 2019 - 2024. All rights reserved.