24.9 maps Package (Go 1.21+): Keys, Values, Clone, Equal

Right, let’s talk about the maps package. You’ve been writing Go for a while, and you’ve undoubtedly written the same three map-related functions a dozen times: one to get a slice of the keys, another for the values, and a third to check if two maps are deeply equal. It’s a rite of passage, like building your own IKEA furniture with a butter knife. It works, but you always feel a little silly doing it when a proper toolkit is available.

24.7 sort.Search: Binary Search

Right, so you want to find something in a sorted slice. You could just loop through it, checking each element one by one. That’s a linear search, and it’s fine for your grocery list. But if you’re dealing with a sorted list of 100,000 users by ID, checking every single one is like reading the dictionary cover-to-cover to find the word “zebra.” It works, but it’s an intellectual embarrassment. This is where sort.Search comes in. It’s Go’s built-in implementation of a binary search, and it’s so fast it feels like cheating. The core idea is simple: you start in the middle of your sorted slice. If the element there is less than your target, you know your target must be in the right half; if it’s greater, it’s in the left half. You then repeat the process on that half, and so on, halving the search space each time. You go from 100,000 elements to 50,000 to 25,000 to… you get the idea. You’ll find your target (or confirm its absence) in about 17 steps. Logarithmic time. Chef’s kiss.

24.6 sort.Slice and sort.Stable: Sorting with Less Functions

Right, let’s talk about sorting slices. You’ve probably tried to sort a []int with sort.Ints and it was blissfully simple. But then you tried to sort a slice of your own structs—a []Person by last name, maybe—and you hit a wall. The built-in sort package doesn’t know your Person from a hole in the ground. That’s where sort.Slice and sort.SliceStable come in. They are your gateway to sorting anything, and they do it by making you do the heavy lifting. It’s the “I’ll hold the light, you fix the engine” approach to sorting.

24.5 math/rand/v2 (Go 1.22+): Seeding and Distributions

Alright, let’s talk about the new hotness: math/rand/v2. It landed in Go 1.22, and frankly, it’s about time. The old math/rand was like that reliable but slightly cranky old car that started most days. The new one is that car’s sleeker, more efficient descendant, with a few of the weird quirks finally fixed. We’re going to focus on two of the biggest upgrades: the end of the tedious seeding dance and the fantastic new buffet of distributions.

24.4 math and math/big: Numeric Operations

Let’s be honest: you’re not here because you love math. You’re here because you need to get numbers to behave. Go’s math package is your no-nonsense Swiss Army knife for this. It’s not a symbolic math library; it’s a collection of fast, precise functions for common (and some uncommon) operations. It’s the kind of friend who will tell you that 0.1 + 0.2 doesn’t equal 0.3 in floating-point land and then hand you the right tool to deal with it.

24.3 time.Ticker and time.Timer

Right, let’s talk about two of Go’s most useful and, frankly, most misused constructs: time.Ticker and time.Timer. These are your tools for telling your code to “do this thing later” or “do this thing repeatedly.” They’re deceptively simple, and that’s where everyone gets tripped up. I’ve seen more production bugs related to these than I care to admit, so pay attention. The core thing to understand is that both Ticker and Timer are channels. That’s it. Their entire API is a single channel, C, of type <-chan time.Time. Their job is to send a value on that channel at the appointed time. The difference is in their cadence: a Timer fires once; a Ticker fires repeatedly until you stop it.

24.2 time.Duration: Nanoseconds, Milliseconds, and Readable Literals

Let’s talk about time.Duration. It’s one of those things in Go that seems simple until you realize you’ve been doing it wrong for six months. At its heart, a Duration is just an int64 underneath, representing a span of time in nanoseconds. Yes, you read that right. Not milliseconds, not seconds, but nanoseconds. One billionth of a second. This choice is simultaneously brilliant and, for the uninitiated, a bit absurd. Why? Because it gives you integer precision over a massive range of time—from about 290 years down to a single nanosecond—without touching floating-point math and its attendant rounding errors. It’s the kind of brutally pragmatic design decision Go is famous for.

24.1 time.Time: Parsing, Formatting, and Arithmetic

Right, let’s talk about time.Time. This is the struct you’ll be holding onto for dear life, the one that represents a single, unambiguous moment in time. Think of it not as a clock on the wall, but as a point on a cosmic timeline that everyone, from a server in Tokyo to your laptop, can agree on. It’s the antidote to the madness of time zones and string parsing. We’re going to make it your best friend.

— joke —

...