[teamai] Push 87 resource(s) from XingfenD
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
# Map Internals Deep Dive
|
||||
|
||||
## Hash Table Structure
|
||||
|
||||
Go maps use hash tables with bucket-based collision resolution. The map header holds:
|
||||
|
||||
- `count` — number of entries
|
||||
- `B` — log₂ of bucket count (2^B buckets total)
|
||||
- `buckets` — pointer to bucket array
|
||||
- `oldbuckets` — pointer to old buckets during growth
|
||||
|
||||
Each bucket holds 8 key-value pairs. Keys and values are stored in separate arrays within buckets to minimize padding waste.
|
||||
|
||||
## Memory Growth and Capacity
|
||||
|
||||
- **Load factor threshold**: 6.5 entries per bucket triggers growth (sweet spot between memory efficiency and collision performance)
|
||||
- **Overflow bucket chains** also trigger growth if too long (prevents O(1)→O(n) degradation)
|
||||
- **Bucket count doubles**: 2^B → 2^(B+1) (efficient rehashing with powers of 2)
|
||||
- **Incremental evacuation**: Old and new buckets coexist during growth; entries move lazily during operations to avoid GC pauses
|
||||
- **No `cap()` function**: Capacity depends on hash distribution and load factor, not a fixed limit. Preallocation (`make(map[string]int, expectedSize)`) is worthwhile for large maps to avoid repeated growth cycles
|
||||
|
||||
## Preallocation
|
||||
|
||||
```go
|
||||
// Without preallocation — multiple growths as entries are added
|
||||
m := map[string]int{}
|
||||
|
||||
// With preallocation — allocates enough buckets upfront
|
||||
m := make(map[string]int, expectedSize)
|
||||
```
|
||||
|
||||
Preallocation avoids repeated growths. The hint is approximate — Go allocates 2^B buckets where 2^B \* 6.5 >= hint.
|
||||
|
||||
## Pointers vs Values
|
||||
|
||||
For large value types, storing pointers reduces copy overhead:
|
||||
|
||||
```go
|
||||
// Large struct — copied on every read/write
|
||||
m := map[string]BigStruct{} // copies large struct
|
||||
|
||||
// Pointer — only pointer is copied
|
||||
m := map[string]*BigStruct{} // copies 8-byte pointer
|
||||
```
|
||||
|
||||
Trade-off: pointer maps add GC pressure. For small structs (< 128 bytes), value maps are typically faster.
|
||||
|
||||
## `maps` Package (Go 1.21+)
|
||||
|
||||
| Function | Description |
|
||||
| --- | --- |
|
||||
| `Clone`, `Equal`, `EqualFunc` | Shallow copy and equality comparison |
|
||||
| `Keys`, `Values`, `All` (1.23+) | Iterators over keys, values, or pairs |
|
||||
| `Collect`, `Insert` (1.23+) | Build maps from iterators or insert entries |
|
||||
|
||||
See `samber/cc-skills-golang@golang-safety` skill for `Clone`, `Equal`, and sorted iteration patterns.
|
||||
|
||||
## Map Key Requirements
|
||||
|
||||
Map keys must be comparable (`==` must work). This includes:
|
||||
|
||||
- All numeric types, `string`, `bool`
|
||||
- Pointers, channels, interfaces (compared by identity)
|
||||
- Arrays of comparable types
|
||||
- Structs where all fields are comparable
|
||||
|
||||
Slices, maps, and functions **cannot** be map keys.
|
||||
Reference in New Issue
Block a user