Go
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions and Methods
-
Section 4: Concurrency
-
Section 5: Packages and Tooling
-
Section 6: More Standard Library
-
Section 7: Building Services
-
Section 8: Advanced Go
-
Section 9: Go in the Cloud-Native Ecosystem
-
Section 10: Data Structures and Algorithms in Go
-
Section 11: Testing and Deployment
-
Section 12: Practical Projects
-
Section 13: More Standard Library Practice
-
Section 14: More Practice Projects
-
Section 15: Design Patterns in Go
-
Section 16: Interview Practice
-
Section 17: Package fmt In Depth
-
Section 18: Package strings and strconv
-
Section 19: Package os and io
-
Section 20: Package time
-
Section 21: Package sort and container
-
Section 22: Package encoding
-
Section 23: Package net/http In Depth
-
Section 24: Package context
-
Section 25: Package regexp and bytes
-
Section 26: Package errors In Depth
-
Section 27: Package crypto and hash
-
Section 28: Package flag and log
-
Section 29: Package sync In Depth
-
Section 30: More Practice Exercises
-
Section 31: Go Modules and Workspaces In Depth
-
Section 32: Generics Deep Dive (Go 1.18+)
-
Section 33: Testing Package In Depth
-
Section 34: More Interview and Whiteboard Practice
-
Section 35: Package math and unicode
-
Section 36: Package path and filepath
-
Section 37: Package database/sql
-
Section 38: Package text/template and html/template
-
Section 39: Package archive and compress
-
Section 40: Lower-Level net Package
-
Section 41: Package runtime and reflect
-
Section 42: Package embed and io/fs
-
Section 43: Go Assembly and CGO Basics
-
Section 44: Building CLIs and TUIs
-
Section 45: Go Performance Tuning
-
Section 46: More Real-World Projects
-
Section 47: Go in Production
-
Section 48: Go Design Patterns
-
Section 49: Go Interfaces Deep Dive
-
Section 50: Final Practice and Review
128: container/list and container/heap
I see this all the time when developers first encounter the container/heap package: they spend ten minutes searching the documentation for a heap.New() function or a Heap struct they can simply instantiate. They assume that, like container/list, the package provides the data structure itself. It doesn't.
// This is the mistake I'm talking about:
h := heap.New() // Error: heap has no function New
In Go, container/heap is not a data structure; it's a set of functions that operate on any type that satisfies the heap.Interface. You provide the storage (usually a slice) and the logic for how to compare elements, and Go provides the algorithms to maintain the heap property. If you try to treat it like a standalone object, you'll just end up frustrated.
Turning a Slice into a Priority Queue
To actually use a heap, you have to build a type that embeds a slice and then implement five specific methods: Len, Less, Swap, Push, and Pop. I know it feels like a lot of boilerplate, but this is what gives you total control over whether you're building a min-heap or a max-heap.
Let's say we're building a priority queue for a job processor where lower numbers mean higher priority. Here is how you actually set that up:
type Job struct {
Name string
Priority int
}
type PriorityQueue []*Job
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
// We want Pop to give us the lowest priority number first
return pq[i].Priority < pq[j].Priority
}
func (pq PriorityQueue) Swap(i, j int) { pq[i], pq[j] = pq[j], pq[i] }
func (pq *PriorityQueue) Push(x any) {
item := x.(*Job)
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() any {
old := *pq
n := len(old)
item := old[n-1]
*pq = old[0 : n-1]
return item
}
// Usage:
jobs := &PriorityQueue{}
heap.Init(jobs)
heap.Push(jobs, &Job{"Clean room", 3})
heap.Push(jobs, &Job{"Stop server fire", 1})
// This will return "Stop server fire" because it has the lowest priority number
highestPriority := heap.Pop(jobs).(*Job)
Notice that Push and Pop use pointer receivers because they modify the slice's length. A common trip-up is forgetting that heap.Push and heap.Pop (the functions in the package) are the ones you call, not the methods on your type. The package functions call your methods internally to reorganize the tree.
When container/list is actually the right tool
Now, let's talk about container/list. If the misconception with heaps is that they are "too hidden," the misconception with lists is that they are "better slices." In 95% of Go code, a slice is faster because of CPU cache locality. Jumping around memory via pointers in a linked list is usually a performance killer.
However, container/list (a doubly linked list) becomes a superpower when you need to perform constant-time insertions or deletions in the middle of a massive collection, provided you already have a reference to the element. This is exactly why it's the backbone of an LRU (Least Recently Used) cache.
In a slice, deleting an element from the middle requires shifting every subsequent element to the left. In a list.List, you just update two pointers.
import "container/list"
l := list.New()
e1 := l.PushFront("First")
e2 := l.PushBack("Last")
// I can move e1 to the back without shifting any other elements in memory
l.MoveToBack(e1)
// Or I can remove an element instantly if I have the *list.Element pointer
l.Remove(e2)
I'll give you my rule of thumb: start with a slice. If you find yourself doing copy() or slicing operations in a loop to delete items from the middle of a 10,000-element list, that's when you switch to container/list.
📋 Practical Task
Build an Emergency Room Triage System
Your task is to implement a triage system for a hospital emergency room. Patients arrive with different severity levels (1 being critical, 5 being minor). The hospital must always treat the most critical patient first, regardless of when they arrived.
Requirements:
- Create a
Patientstruct withName(string) andSeverity(int). - Implement the
heap.Interfaceon aPatientQueuetype (a slice ofPatientpointers). - Ensure the heap is a min-heap based on the
Severityfield (lowest number = highest priority). - Write a
mainfunction that:- Initializes the heap.
- Adds three patients: "John" (Severity 3), "Alice" (Severity 1), and "Bob" (Severity 2).
- Pops them off one by one and prints their names to verify they are treated in the order: Alice, Bob, John.
There are no comments for now.