Skip to content

Archive

Go

100 articles
Go 10 Sep 2026 6 min read

Insert Iterator Pairs into Go Maps with maps.Insert

Sometimes a Go pipeline naturally produces key-value pairs, but the destination is a map you already have. Turning those pairs into a temporary map just to merge it adds a step that doesn’t help. Go 1.23 added maps.Insert for this case. It consumes an iter.Seq2[K, V] and writes each pair into an existing map. Existing keys are overwritten, unrelated entries stay in place, and the iterator can produce values lazily.

Go 10 Sep 2026 5 min read

Find Values and Insertion Points with slices.BinarySearch

When a Go slice is already sorted, scanning it from the beginning to find one value throws away useful information. slices.BinarySearch uses that ordering directly. It returns both an index and a found flag, and the index remains useful even when the target isn’t present. That second behavior is easy to overlook. slices.BinarySearch isn’t only a membership check; it also tells you where a missing value belongs if you want to preserve the slice’s sort order.

Go 10 Sep 2026 4 min read

Find the First Matching Slice Element in Go with slices.IndexFunc

Searching a slice is easy when the element itself is comparable and you already know the exact value. Real programs often need something slightly different: the first queued job, the first expired token, or the first record whose normalized name matches some input. slices.IndexFunc handles that case directly. You provide a predicate, and it returns the index of the first element for which that predicate is true. If nothing matches, it returns -1.

Go 10 Sep 2026 6 min read

Filter Go Slices in Place with slices.DeleteFunc

Filtering a slice often starts with a small loop: inspect each element, keep the ones you want, and return the shorter result. When changing the original backing array is acceptable, slices.DeleteFunc gives that operation a standard-library name and avoids a hand-written compaction loop. The useful detail is in “changing the original backing array.” slices.DeleteFunc isn’t a general-purpose immutable filter. It removes matching elements in place and returns the shortened slice, so it works best when the caller owns the input and no longer needs its old contents.

Go 10 Sep 2026 5 min read

Filter Go Maps In Place with maps.DeleteFunc

Removing map entries by a condition is common when cleaning caches, pruning stale state, or dropping records that no longer belong in a working set. A for range loop with delete works, but when the operation is simply “delete every entry matching this predicate,” maps.DeleteFunc states that intent directly. The function mutates the map you pass to it. That makes it a good fit for owned, mutable state, but a poor fit when callers still need the original contents.

Go 10 Sep 2026 8 min read

Copy Go Maps with maps.Clone Without Sharing Top-Level State

Copying a Go map is easy to get subtly wrong. Assigning one map variable to another doesn’t duplicate the map, so a write through either variable changes the same underlying map. Since Go 1.21, the standard library’s maps.Clone function gives you a concise way to make a separate top-level map. There is one boundary worth understanding before using it: maps.Clone is a shallow clone. Adding, deleting, or replacing entries in the clone won’t change the original map, but nested maps, slices, pointers, and other reference-bearing values can still refer to the same underlying data.

Go 10 Sep 2026 7 min read

Compare Go Slices with Custom Equality Using slices.EqualFunc

Two slices can represent the same information without being directly comparable element by element. One side might contain structs while the other contains strings. Text may need case-insensitive comparison. IDs may arrive in different concrete types even though your application treats them as the same value. When equality depends on a rule rather than Go’s == operator, slices.EqualFunc puts that rule in one place and handles the slice traversal for you.

Go 10 Sep 2026 6 min read

Compare Go Slices Lexicographically with slices.Compare

Sometimes equality isn’t enough. You may need to order version components, compare path segments, choose which byte sequence comes first, or sort records by a slice-valued key. Writing that comparison by hand is straightforward, but the prefix case and the meaning of the return value are easy places to introduce small bugs. For slices whose element type is ordered, slices.Compare provides the standard lexicographic comparison directly. It compares elements from left to right and, when all shared elements match, treats the shorter slice as smaller.

Go 10 Sep 2026 5 min read

Combine Go Slices with slices.Concat

Combining several slices often starts as a tiny append expression and ends with an ownership question: did the result reuse one of the input backing arrays, and can a later append or mutation affect data another part of the program still uses? Since Go 1.22, slices.Concat gives this operation a direct standard-library form. It combines multiple slices into a new slice, which is especially useful when the result should be treated as its own collection rather than as an extension of one input.

Go 10 Sep 2026 6 min read

Check Slice Predicates in Go with slices.ContainsFunc

Sometimes you don’t need the matching element or its position. You only need to answer a yes-or-no question: does this slice contain anything that satisfies a condition? For that case, slices.ContainsFunc is more direct than writing an index loop or calling slices.IndexFunc and comparing its result with -1. It accepts a predicate, checks elements in order, and returns as soon as one matches. What slices.ContainsFunc does The function accepts any slice element type because the predicate decides what counts as a match:

Go 10 Sep 2026 9 min read

Build Lazy Iterators in Go with iter.Seq

A Go API that returns a slice is pleasantly simple, but a slice isn’t always the right contract. Sometimes the caller only needs the first matching value. Sometimes producing each value requires work. Sometimes the complete result could be large enough that building it up front is wasteful. Go 1.23 gives those APIs a standard alternative: iter.Seq. It represents a sequence that produces values on demand and works directly with a for range loop. The useful part isn’t just new syntax. An iter.Seq can hide a container’s representation, avoid an intermediate result slice, and stop producing values as soon as the caller stops iterating.

Go 10 Sep 2026 7 min read

Build Go Maps from Iterators with maps.Collect

An iterator is a convenient way to produce key-value pairs without deciding up front where they’ll be stored. Eventually, though, an API may need an ordinary map. Writing the collection loop yourself is straightforward, but Go 1.23 gives that boundary a standard name: maps.Collect. maps.Collect consumes an iter.Seq2, stores each yielded pair in a newly allocated map, and returns that map. It’s a small helper, but it makes ownership clear: the sequence produces data; Collect creates the destination.

Go 10 Sep 2026 6 min read

Append Iterator Values to Go Slices with slices.AppendSeq

An iterator is convenient while data is flowing through a pipeline, but sooner or later you may need those values in a slice. If you already have a destination slice, collecting the iterator separately and then appending it creates an unnecessary intermediate step. Go 1.23 added slices.AppendSeq for exactly this boundary. It consumes an iter.Seq, appends each yielded value to an existing slice, and returns the resulting slice. What slices.AppendSeq does The function has a compact signature:

Go 08 Sep 2026 9 min read

Use Go Timers Correctly After Go 1.23

Timer code in Go has accumulated a surprising amount of folklore. Older examples warn that time.After leaks resources, insist that every stopped timer channel must be drained, and wrap Timer.Reset in careful stop-and-drain sequences. Those rules were important for older Go programs. They are not all current rules. Go 1.23 changed the implementation and guarantees of channel-based timers. Unreferenced timers can now be garbage collected before they fire, and timer channels use synchronous semantics that prevent stale values after Stop or Reset returns. The result is simpler timer code—but only when the program is actually using the new semantics.

Go 08 Sep 2026 7 min read

Run Cleanup After Context Cancellation with context.AfterFunc

Cancellation often means more than telling a goroutine to stop. A blocked operation may need to be interrupted, a temporary resource may need cleanup, or some state may need to be released as soon as a request deadline expires. A common approach is to start another goroutine that waits on ctx.Done(). That works, but it adds lifecycle code every time you need cancellation-triggered behavior. Since Go 1.21, the standard context package provides context.AfterFunc for this job.

Go 08 Sep 2026 7 min read

Detach Go Work Safely with context.WithoutCancel

Request cancellation is usually exactly what a Go service wants. When a client disconnects or a request deadline expires, database calls, HTTP requests, and other downstream work should normally stop too. Sometimes one small piece of work has a different lifetime. A handler may need to enqueue an audit record, finish a bounded cache update, or send a best-effort notification after the request itself is no longer alive. Passing the request context directly makes that work inherit cancellation. Replacing it with context.Background() avoids cancellation, but also throws away useful request-scoped values.

Go 07 Sep 2026 11 min read

Suppress Duplicate Concurrent Work in Go with singleflight

A service can become overloaded even when each individual request is reasonable. Imagine a popular product whose cached record expires. Fifty requests arrive almost together, all observe the same cache miss, and all start the same database query. The problem is not ordinary parallelism. Those requests are doing duplicate work for the same result at the same time. golang.org/x/sync/singleflight provides a small mechanism for suppressing that duplication inside one Go process. For a given key, one caller performs the work while concurrent callers for the same key wait and receive the same result. Calls using different keys can still perform their own work.

Go 07 Sep 2026 12 min read

Read Large Line-Oriented Input Safely in Go with bufio.Scanner

Line-oriented input looks simple until one record is much larger than expected. A program may process thousands of ordinary log lines correctly, then stop on a generated stack trace, a large JSON record, or a malformed input that contains no newline for megabytes. Go’s bufio.Scanner is convenient for this job because it handles tokenization and defaults to scanning lines. But that convenience comes with an important boundary: a scanner has a maximum token size. If a token cannot fit within that limit, scanning stops with an error.

Go 07 Sep 2026 11 min read

Read File Regions Safely in Go with io.ReaderAt

Many file formats are not consumed strictly from beginning to end. An index may point to records at known offsets. A binary container may keep metadata in a header and payloads elsewhere. A server may need to serve several independent byte ranges from the same open file. The obvious approach is to call Seek, then Read. That works when one goroutine owns the file position. It becomes fragile when several operations share the same file because the current offset is mutable state.

Go 07 Sep 2026 14 min read

Observe Streaming Reads in Go with io.TeeReader

Streaming code often needs to do two things with the same bytes. A service may need to parse a response while computing its checksum. A file importer may want to decode records while recording exactly what the decoder consumed. A diagnostic tool may want to inspect a stream without first loading the entire input into memory. A common but wasteful approach is to read everything into a byte slice and then run each operation over that copy. That is simple for small inputs, but it removes the main advantage of streaming: work can begin before the whole input has arrived, and memory usage does not have to grow with the full input size.

Go 07 Sep 2026 9 min read

Handle Go HTTP Response Bodies Without Leaking Connections

An HTTP request can appear to work while quietly making later requests more expensive. A common cause in Go clients is mishandling http.Response.Body: forgetting to close it, returning before cleanup is arranged, or assuming that an HTTP error status is returned as a Go error. The important mental model is that a successful Client.Do call gives your code ownership of a stream, not a byte slice. The response headers have arrived, but the body is consumed as you read it. Your code must decide how much of that stream it needs and must close it when finished.

Go 07 Sep 2026 12 min read

Compose Sequential Streams in Go with io.MultiReader

Programs often need to present several pieces of data as one input stream. A request body may need a generated header followed by a file. A test may need a prefix, a fixture, and a suffix. A protocol adapter may need to expose several existing readers through an API that accepts only one io.Reader. The obvious solution is to read every piece into memory, concatenate the byte slices, and create a new reader over the result. That is reasonable for small, already-buffered data. It is a poor fit when one source is large, slow, or naturally streaming because the consumer cannot start until the combined buffer has been built.

Go 07 Sep 2026 7 min read

Combine Independent Failures in Go with errors.Join

A function sometimes performs several independent operations and more than one can fail. Cleanup is a common example: closing one resource should not prevent the program from attempting to close the next. Validation can have the same shape when callers benefit from seeing several independent problems at once. Returning only the last error loses information. Returning only the first error may hide failures that happened later. Go’s errors.Join provides a standard way to return one error value that still wraps multiple underlying errors.

Go 06 Sep 2026 9 min read

Handle Long Lines Safely in Go with bufio.Scanner

bufio.Scanner is one of the simplest ways to process line-oriented input in Go. It is a good fit for log files, command output, newline-delimited JSON, and other formats where one logical record fits in memory. The convenience has an important boundary: a Scanner will stop if the next token grows beyond the amount of buffering it is allowed to use. That default protects a program from growing memory without bound, but it can surprise code that works on small test files and later encounters one unusually long line in production.