算法艺术创作
algorithmic-art
通过代码和可调参数创作生成艺术与交互式视觉效果。
go-data-structures【设计与创意】Correct use of Go's built-in data structures: slices (nil vs empty, append semantics, aliasing, preallocation), maps (comma-ok, sets, iteration order), arrays, and choosing between them. Use when: "slice vs array", "nil slice", "empty slice", "preallocate", "map iteration", "use a set in Go", "slice aliasing", "append gotcha", "copy a slice", "sync.M…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Slices and maps look simple and hide the sharpest edges in the language. These rules prevent the aliasing, nil, and iteration bugs that survive code review.
var a []int // nil slice — len 0, cap 0, no allocation
b := []int{} // empty slice — len 0, allocated header
c := make([]int, 0) // empty slice — same as b
len, cap, range, and append treat all three identically.nil marshals to null, empty marshals to [].
If the API contract requires [], return an empty slice explicitly.len(s) == 0.append MAY return the same backing array or a new one. Both cases
bite:
// ❌ Bad — result may alias the input
func addSuffix(base []string) []string {
return append(base, "suffix") // if cap(base) > len(base),
} // this WRITES INTO base's array
// ✅ Good — force a copy when the input must not be touched
func addSuffix(base []string) []string {
out := make([]string, len(base), len(base)+1)
copy(out, base)
return append(out, "suffix")
}
// ❌ Bad — subslice keeps the whole 64 MB alive
func header(big []byte) []byte {
return big[:512] // backing array is still the full big
}
// ✅ Good — copy the window you keep
func header(big []byte) []byte {
return slices.Clone(big[:512]) // Go 1.21+; or copy() manually
}
Rule: a function either owns a slice or copies it. Returning a subslice of a caller's slice, or appending to one, silently shares memory.
When the final size is known or bounded, allocate once:
// ✅ Good — one allocation
names := make([]string, 0, len(users))
for _, u := range users {
names = append(names, u.Name)
}
// ❌ Bad — repeated growth and copying
var names []string
for _, u := range users {
names = append(names, u.Name)
}
Same for maps: make(map[string]int, len(items)).
Don't preallocate when the size is unknown — a wrong large cap wastes
memory; append growth is fine for cold paths.
// Comma-ok distinguishes "missing" from "zero value"
count, ok := hits[key]
if !ok { /* key absent */ }
// Zero value reads are safe; writes to a nil map PANIC
var m map[string]int
_ = m["x"] // 0, fine
m["x"] = 1 // panic: assignment to entry in nil map — make() first
// Iteration order is RANDOM and differs between runs.
// Sort keys when output must be deterministic:
keys := slices.Sorted(maps.Keys(m)) // Go 1.23+
for _, k := range keys {
fmt.Println(k, m[k])
}
m[k].Field = v doesn't compile for
struct values. Use a map of pointers, or read-modify-write.range is safe; inserting during range is
unspecified (the new key may or may not be visited).The idiomatic set is a map with empty-struct values:
seen := make(map[string]struct{}, len(items))
for _, it := range items {
if _, dup := seen[it.ID]; dup {
continue
}
seen[it.ID] = struct{}{}
process(it)
}
struct{} occupies zero bytes; map[string]bool also works and reads
better when you'll test membership with if seen[id].
[4]byte) are values: assignment and passing copy the whole
array. Comparable with == when elements are comparable.[32]byte), IPv4 addresses, fixed matrices, map keys.[100]int copies 800
bytes per call — almost always wrong.| Need | Use |
|---|---|
| Ordered collection, growable | []T |
| Membership / dedup | map[K]struct{} |
| Key→value lookup | map[K]V |
| Fixed size, value semantics, comparable | [N]T array |
| FIFO queue (single goroutine) | slice with head index, or container/list for heavy churn |
| Stack | slice + append / s[:len(s)-1] |
| Concurrent map, write-once read-many keys | sync.Map — otherwise mutex + map |
sync.Map is a special-case tool (append-only caches, disjoint key
sets). Default to map + sync.RWMutex; see the concurrency skill for
locking patterns.
len() used for emptiness[]append to a slice the function doesn't own; copies made explicitslices.Clone/copymap[K]struct{} (or map[K]bool for readability)