go-data-structures

Use when working with Go slices, maps, or arrays — choosing between new and make, using append, declaring empty slices (nil vs literal for JSON), implementing…

INSTALLATION
npx skills add https://github.com/cxuu/golang-skills --skill go-data-structures
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

Go Data Structures

Choosing a Data Structure

What do you need?

├─ Ordered collection of items

│  ├─ Fixed size known at compile time → Array [N]T

│  └─ Dynamic size → Slice []T

│     ├─ Know approximate size? → make([]T, 0, capacity)

│     └─ Unknown size or nil-safe for JSON? → var s []T (nil)

├─ Key-value lookup

│  └─ Map map[K]V

│     ├─ Know approximate size? → make(map[K]V, capacity)

│     └─ Need a set? → map[T]struct{} (zero-size values)

└─ Need to pass to a function?

   └─ Copy at the boundary if the caller might mutate it

When this skill does NOT apply: For concurrent access to data structures (mutexes, atomic operations), see go-concurrency. For defensive copying at API boundaries, see go-defensive. For pre-sizing capacity for performance, see go-performance.

Slices

The append Function

Always assign the result — the underlying array may change:

x := []int{1, 2, 3}

x = append(x, 4, 5, 6)

// Append a slice to a slice

x = append(x, y...)  // Note the ...

Two-Dimensional Slices

Independent inner slices (can grow/shrink independently):

picture := make([][]uint8, YSize)

for i := range picture {

    picture[i] = make([]uint8, XSize)

}

Single allocation (more efficient for fixed sizes):

picture := make([][]uint8, YSize)

pixels := make([]uint8, XSize*YSize)

for i := range picture {

    picture[i], pixels = pixels[:XSize], pixels[XSize:]

}

Read references/SLICES.md when debugging unexpected slice behavior, sharing slices across goroutines, or working with slice headers.

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.

Exception for JSON: A nil slice encodes to null, while []string{}

encodes to []. Use non-nil when you need a JSON array.

When designing interfaces, avoid distinguishing between nil and non-nil

zero-length slices.

Maps

Implementing a Set

Use map[T]bool — idiomatic and reads naturally:

attended := map[string]bool{"Ann": true, "Joe": true}

if attended[person] {  // false if not in map

    fmt.Println(person, "was at the meeting")

}

Copying

Be careful when copying a struct from another package. If the type has methods

on its pointer type (*T), copying the value can cause aliasing bugs.

General rule: Do not copy a value of type T if its methods are associated

with the pointer type *T. This applies to bytes.Buffer, sync.Mutex,

sync.WaitGroup, and types containing them.

// Bad: copying a mutex

var mu sync.Mutex

mu2 := mu  // almost always a bug

// Good: pass by pointer

func increment(sc *SafeCounter) {

    sc.mu.Lock()

    sc.count++

    sc.mu.Unlock()

}

Quick Reference

Topic

Key Point

Slices

Always assign append result; nil slice preferred over []T{}

Sets

map[T]bool is idiomatic

Copying

Don't copy T if methods are on *T; beware aliasing

Related Skills

  • Defensive copying: See go-defensive when copying slices or maps at API boundaries to prevent mutation
  • Capacity hints: See go-performance when pre-sizing slices or maps for known workloads
  • Iteration patterns: See go-control-flow when using range loops over slices, maps, or channels
  • Declaration style: See go-declarations when choosing between new, make, var, and composite literals
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card