必须调用heap.fix,因为container/heap不监听字段变化,仅在push/pop/fix时执行上滤或下滤;手动改优先级后不fix,堆序失效,后续pop可能返回错误元素或触发nil指针panic。

更新堆中元素优先级不能靠重新 Push 或改字段后不管——必须调用 heap.Fix,否则堆序立即失效。
为什么直接改字段后不调 heap.Fix 就 panic 或乱序?
container/heap 不监听字段变化,它只在 Push、Pop、Fix 时做上滤或下滤。你手动改了某个元素的 Priority 字段,但没告诉 heap 这个位置已失序,后续 Pop 可能返回错误元素,甚至触发 Less 中的 nil 指针 panic(比如字段刚被设为 nil 但没修复)。
-
Less方法每次比较都访问字段,改完不修复 → 下一次堆调整就拿错值比 - 如果该元素原本在叶子,改高优先级后应上浮;改低后应下沉——不
Fix就永远卡在原位 - 别试图用
heap.Init替代Fix:它是全量重建(O(n)),而Fix是单点修复(O(log n))
heap.Fix 的参数和调用时机怎么写才对?
heap.Fix 要传两个参数:&h(指针)和 i(失序元素在切片中的索引)。这个 i 必须是你能准确拿到的——通常存在结构体字段里(如 item.index),不能靠 sort.Search 临时找(慢且不准)。
- 初始化时就得把
index字段写进每个*Item,并在Swap方法里同步更新它 - 更新字段后立刻调
heap.Fix(&pq, item.index),不是等 Pop 时再补 - 如果改的是多个元素,别循环调
Fix,先批量改完,再对每个索引调一次——重复调同一个索引无害,但漏掉一个就崩
常见错误:在 Less 里读未同步的 index 或访问 nil 字段
Less(i, j int) bool 里的 i 和 j 是 heap 内部算出来的索引,不是你存的 item.index。如果你在 Less 里误用 h[i].index 做逻辑判断,或者没判空就访问 h[i].Task.ExecAt,运行时直接 panic。
-
Less只干一件事:比较h[i]和h[j]的业务优先级字段,其他逻辑一律剥离 - 字段可能为 nil?加守卫:
h[i].Task != nil && h[i].Task.Priority > h[j].Task.Priority - 别在
Less里查 map、调函数、做 I/O——它每轮 sift 都被调多次,一卡整个调度循环
最易忽略的一点:更新优先级后,item.index 字段本身不会自动变——Fix 会挪动元素位置,但不会回填新索引。如果你后续还要再更新,得在 Swap 方法里维护它,否则下次 Fix 就传错坐标。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











