如何编写pop()函数

时间:2017-02-26 11:30:35

标签: go

localStorage.getItem('asdf')

如何为任何类型的数组创建一个a := []int{1,2,3} x, a := a[len(a)-1], a[:len(a)-1] fmt.Println(a,x) 函数?

这是我到目前为止所提出的:

pop()

但如果我尝试通过反复试验来调整代码,我会收到func pop(a []*interface{}) interface{}{ x := a[len(a)-1] a = a[:len(a)-1] return x } func main(){ a := []int{1,2,3} x = pop(a) fmt.Println(a,x) // -> [1,2] 3 } 或其他错误消息。

3 个答案:

答案 0 :(得分:2)

package main

import (
    "fmt"
    "reflect"
)

func pop(a interface{}) interface{} {
    v := reflect.ValueOf(a).Elem()
    x := v.Index(v.Len() - 1)
    v.SetLen(v.Len() - 1)
    return x
}

func main() {
    a := []int{1, 2, 3}
    x := pop(&a)
    fmt.Println(a, x) // ->  [1,2] 3
}

虽然可以实现,但我仍然认为x, a = a[len(a)-1], a[:len(a)-1]应该优于pop函数。

答案 1 :(得分:0)

go类型系统不允许你从[]type1 -> []type2投射。即使它确实接口是一个包含类型id和指向对象的指针的结构,通常你只需拥有该对象。因此,您需要使用interface{}并使用反射进行切片。

func pop(slice interface{}) (interface{}, interface{}) {
    v := reflect.ValueOf(slice)
    return v.Slice(0,v.Len()-1).Interface(), v.Index(v.Len()-1).Interface()
}

Go Playground

请注意,这会丢失编译时类型安全性,因为它必须使用接口。此外,由于使用接口,可以分配poped值,从而产生额外的GC压力。

Common Go风格通常建议不要编写这样的函数,只是手动内联少量代码。

答案 2 :(得分:0)

在使用反射完成所有非常好的回答后,我还想添加一个答案,提供更具惯用性的Go解决方案。就像Rob Pike在他关于Go Proverbs

的精彩演讲中所说的那样
  • interface {}什么也没说
  • 反思永远不清楚

所以应该有一个答案显示惯用的Go方式。此解决方案不适用于标准类型的切片。但是 cshu 的答案显示了最佳解决方案:b

对于自己定义的类型,我们必须定义一个Poper接口,Pop函数将其作为输入并返回一个空接口。

2.0

https://play.golang.org/p/UbDkoVYSMA

返回空接口并不是一个好主意,因为以下所有代码都必须支持接口{}。

以下代码示例不起作用:

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

https://play.golang.org/p/wg9__O44A8

错误说明了该问题:不能在赋值中使用Pop(a)(类型接口{})作为int类型:need type assertion

所以Pop()函数通过返回接口{}来工作,但是使用该函数的结果的其余代码需要进行类型断言。因此,如果您可以避免它,您应该使用类型搜索另一个解决方案。