agentleFS
h0rn3th0rn3t/golang-skills/skills/go-data-structures/SKILL.md

go-data-structures

Skill7 starsChanged 9 days agoApache-2.0View on GitHub

Use when creating or manipulating Go slices, maps, arrays, or sets, including new/make, append, copies, and nil versus empty JSON collections. Thread safety belongs to go-concurrency.

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 4 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈4

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    When updates must overwrite matching keys before filtering the resulting map:

    line 63
  2. Distinctive:

    Prefer nil slices over empty literals:

    line 75
  3. Distinctive:

    When designing interfaces, avoid distinguishing between nil and non-nil zero-length slices.

    line 95
  4. Very specific:

    Use map[T]struct{} when the map is only a set.

    line 104
  5. Distinctive:

    Use boolean map values only when the value carries a separate meaning beyond presence.

    line 107

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Go Data Structures

Compatibility: Baseline Go 1.27 (see COMPATIBILITY.md). slices/maps and slices.Clone/maps.Clone require Go 1.21+; slices.Concat Go 1.22+; strings.CutLast/bytes.CutLast Go 1.27+.

Resource Routing

  • references/SLICES.md - Read when managing slice capacity and aliasing, or when a subslice keeps a large backing array alive.

Slices

Reach for slices and maps First

The slices and maps packages (Go 1.21+) cover most hand-written loops. Writing the loop instead is a reviewable defect, not a style choice. go fix -diff on the edited package previews the loops a fixer exists for (slicescontains, slicesbackward, slicessort, mapsloop, minmax); Equal, Concat, Insert, and Delete have none and are written by hand.

Loop you were about to writeUse
Compareslices.Equal, maps.Equal
Concatenateslices.Concat (Go 1.22+)
Insert/delete in the middleslices.Insert, slices.Delete
Iterate in reverseslices.Backward (Go 1.23+)
Split off the last segmentstrings.CutLast / bytes.CutLast (Go 1.27+)
ns, name, ok := strings.CutLast(key, ".") // "app.http.requests" → "app.http", "requests", true
if !ok {
    ns, name = "", key // no ".": CutLast returned key, "", false
}

slices.Clone and maps.Clone preserve nilness: nil input yields nil, while an initialized empty container stays non-nil. slices.Collect, slices.Sorted, and slices.Concat return nil for an empty result — Concat even when every input is a non-nil empty slice. An unconditional make plus copy produces a non-nil container even for nil input. Preserve that allocation when JSON, a later map write, or observable capacity requires it — see Declaring Empty Slices. Check the contract before replacing a loop:

all := slices.Concat(a, b)
if all == nil {
    all = []Item{} // encoding/json v1 writes nil as null; this list's contract is []
}

These clones are shallow: references inside elements or map values remain shared. Copy depth and type-specific Clone contracts belong to go-defensive.

Update and Filter an Existing Map

When updates must overwrite matching keys before filtering the resulting map:

maps.Copy(dst, updates)
maps.DeleteFunc(dst, func(_ string, score int) bool { return score < minimum })

Both operations mutate dst, so existing aliases observe the changes. The destination must be initialized if the source contains entries.

Declaring Empty Slices

Prefer nil slices over empty literals:

// Good: nil slice
var t []string

// Avoid: non-nil but zero-length
t := []string{}

Both have len and cap of zero, but the nil slice is the preferred style.

JSON depends on the encoder: encoding/json v1 encodes a nil slice or nil map as null, and []string{} as [], map[string]int{} as {}. JSON v2 defaults encode nil non-byte slices as [] and nil maps as {}; FormatNilSliceAsNull(true) and FormatNilMapAsNull(true) restore null. Require non-nil only when the selected encoder/options or another caller contract needs it. See JSON v2 defaults.

When designing interfaces, avoid distinguishing between nil and non-nil zero-length slices.


Maps

Implementing a Set

Use map[T]struct{} when the map is only a set. The empty struct takes no storage and makes membership intent explicit.

Use boolean map values only when the value carries a separate meaning beyond presence.

A Map Never Shrinks

delete and clear free the values but keep the table at its peak size (measured on Go 1.27: 500K keys at 30 MiB stay at 26 MiB after either). A map whose size swings — per-window counters, a swept cache, a limiter reset — is reset by assigning a fresh make, and the old one is collected.


Copying

A struct whose methods have pointer receivers or that holds a lock (bytes.Buffer, sync.Mutex) is passed by pointer, never copied — except a value type whose only pointer methods are decoders, such as time.Time; go-functions owns the rule.


Related Skills

  • go-defensive: copying slices and maps at API boundaries.
  • go-performance: capacity hints for known workloads.
  • go-style-core: range forms and new/make/var/literal choices.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.