【问题标题】:Why is the slice sometimes passed by reference, sometimes by pointer?为什么切片有时通过引用传递,有时通过指针传递?
【发布时间】:2015-05-07 12:00:27
【问题描述】:

在 go 中默认的 container/heap 包中,有一个实现优先级队列的示例。

在查看the sample code时,它使用了一个切片[]*Item,并实现了heap.Interface

我的麻烦在于以下几点。为什么有些函数将优先级队列声明为切片,有时声明为切片指针?:

func (pq PriorityQueue) Swap(i, j int) {...}
// vs
func (pq *PriorityQueue) Push(x interface{}) {...}

为什么不总是 (pq PriorityQueue) ?在另一个StackOverflow thread about pointer to slices 上,文档说切片是引用类型,那么为什么要在它们上使用指针呢?我遇到了这样一个事实,即官方文档说了一些话,然后将两者混合在一起,而没有解释添加指针的意义。

感谢您的见解!

编辑: 这是一个例子:

// original sample code from the docs:
func (pq *PriorityQueue) Push(x interface{}) {
    n := len(*pq)
    item := x.(*Item)
    item.index = n
    *pq = append(*pq, item)
}

// is this the same (removed pointers to slice) ?
func (pq PriorityQueue) Push(x interface{}) {
    n := len(pq)
    item := x.(*Item)
    item.index = n
    pq = append(pq, item)
}

如果两个函数相同,为什么现在使用指针?

【问题讨论】:

    标签: pointers go


    【解决方案1】:

    Go 博客上的This article 解释了原因。

    将切片传递给函数部分:

    了解即使切片包含 指针,它本身就是一个值。在幕后,它是一个结构值 拿着一个指针和一个长度。它不是指向结构的指针。

    因此,您要么需要传递一个指针,要么需要将切片作为值返回,如果您想使用 append 对其进行修改。

    如果您只想修改切片的内容,您可以简单地通过值传递切片:

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

    通过追加,您正在修改切片标题。和

    因此,如果我们要编写一个修改标头的函数,我们必须 将其作为结果参数返回

    或者:

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

    【讨论】:

    • 感谢您提供的信息,但我仍然不明白他们为什么在示例代码中间更改了函数原型。我在问题的底部添加了一个示例来说明这一点。
    • 交换和推送做不同的事情。交换只改变切片的内容。 Push 添加到切片中,从而改变切片的长度,即切片头。因此,您需要一个指针(或返回修改后的副本)。您的第二个示例将不起作用,因为 append 将修改切片标头的副本。
    • 如果您查看堆示例,它在 cmets 中正确显示:// Push and Pop use pointer receivers because they modify the slice's length, not just its contents.
    • 哦,对了,我没有展开 IntHeap 示例!我还找到了this useful SO post about a strange Pop method has no pointer receiver error
    猜你喜欢
    • 2010-09-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-27
    • 2023-03-03
    • 2011-04-06
    相关资源
    最近更新 更多