Go 将heap.Interface作为结构

Go 将heap.Interface作为结构,go,Go,我正在使用Go的包创建一个优先级队列。文件中有一个 我正在创建的队列需要基于结构而不是切片,因为它需要其他属性,如互斥体 type PQueue struct { queue []*Item sync.Mutex } 我实现了所有需要的方法 问题是我的PQueue.Push方法似乎没有永久性地向PQueue.queue添加值 func (p PQueue) Push(x interface{}) { p.Lock() defer p.Unlock() i

我正在使用Go的包创建一个优先级队列。文件中有一个

我正在创建的队列需要基于结构而不是切片,因为它需要其他属性,如互斥体

type PQueue struct {
    queue []*Item
    sync.Mutex
}
我实现了所有需要的方法

问题是我的
PQueue.Push
方法似乎没有永久性地向
PQueue.queue
添加值

func (p PQueue) Push(x interface{}) {
    p.Lock()
    defer p.Unlock()
    item := x.(*Item)
    item.place = len(p.queue) // the index of an item in the queue
    p.queue = append(p.queue, item)
    // len(p.queue) does increase
    // after the functions exits, the queues length has not increased
}
如果我在此函数末尾打印
p.queue
的长度,则长度增加。然而,在函数退出之后,原始结构似乎没有得到更新

我认为这可能是因为
func(p PQueue)
不是指针。为什么会这样?有办法解决吗?如果我使用
func(p*PQeueue)Push(x interface{})
来代替,我需要实现自己的堆,因为
heap.interface
特别不需要指针。这是我唯一的选择吗

我认为这可能是因为func(pPQUE)不是指针

对。引述:

对值调用[the method]将导致该方法接收 值的副本,因此将放弃任何修改

你说:

接口特别不需要指针

我很困惑,您所指的示例实际上是使用指针:

func (pq *PriorityQueue) Push(x interface{}) {
    n := len(*pq)
    item := x.(*Item)
    item.index = n
    *pq = append(*pq, item)
}
也许发生了什么事

我认为这可能是因为func(pPQUE)不是指针

对。引述:

对值调用[the method]将导致该方法接收 值的副本,因此将放弃任何修改

你说:

接口特别不需要指针

我很困惑,您所指的示例实际上是使用指针:

func (pq *PriorityQueue) Push(x interface{}) {
    n := len(*pq)
    item := x.(*Item)
    item.index = n
    *pq = append(*pq, item)
}

可能发生了其他事情?

关于与
Push
方法的接收器相关的问题,您是对的:该方法将接收
PQueue
的副本,因此对结构所做的任何更改都不会持续

将方法更改为使用指针作为接收器是正确的更改,但这也意味着
PQueue
不再实现
heap.Interface
。这是因为Go不允许使用指针指向存储在接口变量中的值,因此不会自动将
q.Push()
转换为
(&q).Push()


但这并不是死胡同,因为
*PQueue
仍然应该实现
堆接口。因此,如果您以前调用的是
heap.Init(q)
,只需将其更改为
heap.Init(&q)
,您的问题与
Push
方法的接收者相关,这是正确的:该方法将接收
PQueue
的副本,因此对结构所做的任何更改都不会持久

将方法更改为使用指针作为接收器是正确的更改,但这也意味着
PQueue
不再实现
heap.Interface
。这是因为Go不允许使用指针指向存储在接口变量中的值,因此不会自动将
q.Push()
转换为
(&q).Push()


但这并不是死胡同,因为
*PQueue
仍然应该实现
堆接口。因此,如果您以前调用的是
heap.Init(q)
,只需将其更改为
heap.Init(&q)

,问题是您正在附加到切片的副本。因此,更改将显示在函数中,但一旦从函数返回,更改将丢失

在将切片传递给函数的部分中

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

使用append可以修改切片标头。及

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

或:

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

因此,如果要使用append修改指针,则需要传递指针。只需将方法更改为使用指针接收器。要实现这一点,您需要使用类似于
heap.init(&pq)
的指针调用init,如您链接到的示例所示,该示例正是这样做的,并且还使用指针接收器

从方法集上的

对应指针类型*T的方法集是所有方法的集合 用receiver*T或T声明(也就是说,它还包含方法 一组T)


因此,使用指针类型将与值和指针接收器一起工作,并且仍然实现接口。

问题在于,您正在附加到切片的副本。因此,更改将显示在函数中,但一旦从函数返回,更改将丢失

在将切片传递给函数的部分中

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

使用append可以修改切片标头。及

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

或:

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

因此,如果要使用append修改指针,则需要传递指针。只需将方法更改为使用指针接收器。为了实现这一点,您需要使用类似于
heap.init(&pq)
的指针调用init,如您链接到的示例所示,该示例正是这样做的,并且还使用指针接收器