在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?
链接文档中的“剪切”技巧可以满足您的需求:
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)
如果你想编写一个以类似于 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)
您可以声明
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]
另一种选择是创建一个函数,该函数接受一个指向 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
}
xs := []int{1, 2, 3} // => xs=[1, 2, 3]
x := pop(&xs) // => xs=[1, 2], x=3
我不确定是否有“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
另请参阅:
我会做一些类似于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]
}
这是一个使用指针就地修改列表的版本,同时支持可选的“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
}