指针和切片参考类型 - 接收器

时间:2015-04-24 03:32:11

标签: go

我认为一旦它被叫到我就会有点明显,但是现在以下不是点击。

type Stack []interface{}

func (stack *Stack) Push(x interface{}) {
    *stack = append(*stack, x)
}

我有一个名为Stack的类型,它是一个空接口片。鉴于它是空的,Push方法满足接口。假设切片是一个引用类型,为什么“堆栈”接收器不能通过值传入?此外,在上面的例子中,接收器作为指针传递为什么追加内置需要再次通过指针传递?

IE为什么不能这样做,因为切片是指向底层数组的引用指针?

func (stack Stack) Push(x interface{}) {
    stack = append(stack, x)
}

2 个答案:

答案 0 :(得分:7)

article on the Go blog。它详细解释了正在发生的事情并完全回答了您的问题。

将切片传递给函数

部分
  

重要的是要理解即使切片包含指针,它本身也是一个值。在封面下,它是一个包含指针和长度的结构值。它不是指向结构的指针。

因此,您需要一个指针接收器,或者如果要使用append修改它,则需要将切片作为值返回。

如果您只想修改切片的内容,只需按值传递切片:

  

即使切片标头按值传递,标头也包含一个   指向数组元素的指针,因此原始切片头和   传递给函数的头文件副本描述了相同的数组。   因此,当函数返回时,修改后的元素可以是   通过原始切片变量看到。

使用append修改切片标头。和

  

因此,如果我们想编写一个修改标题的函数,我们必须这样做   将其作为结果参数返回

或者:

  

让函数修改切片标头的另一种方法是传递指向它的指针。

你似乎也对使用指针感到困惑。请参阅spec

  

对于类型为T的操作数x,地址操作& x生成* T到x的指针。

  

对于指针类型* T的操作数x,指针间接* x表示由x指向的类型T的变量。

因此,您的示例*stack = append(*stack, x)并不意味着您正在向append传递指针,恰恰相反 - 您正在取消引用指针以传递它指向的值。

答案 1 :(得分:2)

您遇到的问题是append返回对新切片的引用。除非是指针,否则不能更改函数接收器的值。

我建议的是制作一个包装结构:

type Stack struct{
   data []interface{}
   size int
}
func (s *Stack) Push(i interface{}){
   s.data = append(s.data,i)
   s.size++
}