Slices share memory, maps start out nil, and append sometimes copies. This guide explains the picture behind each one so the surprises stop being surprising.
Go keeps its language small, but slices and maps still trip up newcomers. The code compiles, the logic looks fine, and then one list changes when you did not touch it, or a program panics on a map you thought was ready.
Both have a simple mental picture behind them. Learn the picture and the surprises make sense.
By the end you will be able to:
- Describe what a slice really is and why two slices can share data.
- Explain
len,capand whatappenddoes. - Create, read, update and delete map entries safely.
- Avoid the three classic mistakes with each.
Arrays are fixed, slices are flexible
An array in Go has a fixed length that is part of its type. [3]int and [4]int are different types. That is rarely what you want, so in everyday Go you use slices.
A slice does not hold the data itself. It is a small description of a window onto an array: where the window starts, how many items are in it (len), and how far it could stretch (cap).
nums := []int{10, 20, 30, 40, 50}
s := nums[1:4]
fmt.Println(s) // [20 30 40]
fmt.Println(len(s)) // 3
fmt.Println(cap(s)) // 4 (from index 1 to the end of the array)What append does
append adds items to the end. If the underlying array has spare room (cap is bigger than len) it writes into that room. If not, Go allocates a bigger array, copies everything across, and gives you a slice pointing at the new one.
Maps: look things up by key
A map stores key and value pairs and finds a value quickly from its key. The type reads as map[KeyType]ValueType.
ages := map[string]int{
"asha": 31,
"ravi": 28,
}
ages["meera"] = 35 // add or update
delete(ages, "ravi") // remove
age, ok := ages["asha"] // the "comma ok" check
if ok {
fmt.Println("Asha is", age)
}The ok value matters. Reading a missing key does not fail. It quietly gives you the zero value (0 for an int), which looks exactly like a real zero. Use the comma-ok form whenever “missing” and “zero” mean different things.
for name, age := range ages {
fmt.Println(name, age)
}
// Order is not guaranteed and can change between runs.Three map mistakes to avoid
- Writing to a nil map.
var m map[string]intgives you a nil map. Reading is fine, but writing panics. Create it withmake(map[string]int)or a literal first. - Expecting a fixed order. Go deliberately randomizes iteration order. Sort the keys if you need a stable order.
- Sharing a map between goroutines. Concurrent writes crash the program. Protect the map with a
sync.Mutex, or usesync.Mapfor special cases.
Quick reference
| Task | Slice | Map |
|---|---|---|
| Create | make([]int, 0) or []int{1, 2} | make(map[string]int) or a literal |
| Add | s = append(s, x) | m[key] = value |
| Remove | Re-slice, or use the slices package | delete(m, key) |
| Size | len(s) | len(m) |
| Ordered? | Yes | No |