# Collections

So far you've held one value at a time. Real programs deal in *many* - a list of users, a table of
prices, the words in a sentence. One decision trips up newcomers: arrays versus slices. Clear that up
first, and everything else falls into place.

## Arrays vs slices - the distinction that matters

An **array** in Go is a fixed-size sequence of values, all the same type. The size is part of the type:
`[3]int` is "exactly three integers" - not two, not four. You can't grow it, which makes arrays rare in
everyday Go.

A **slice** is a *flexible-length* view onto a sequence of values. It can grow and shrink, and it's what
Go programmers use almost all the time - "a list that can change size." Its type has no number: `[]int`
is "a list of integers, however many."

📝 **Terminology.** The empty brackets are the tell. **`[3]int`** (number inside) = array, fixed.
**`[]int`** (nothing inside) = slice, flexible. When in doubt, you want the slice.

Here's a slice in action:
```go
package main

import "fmt"

func main() {
	primes := []int{2, 3, 5, 7}
	fmt.Println(primes)
	fmt.Println(primes[0], primes[3])
}
```
```console
$ go run main.go
[2 3 5 7]
2 7
```
`[]int{2, 3, 5, 7}` created a slice of four integers, printed in brackets. `primes[0]` reads the **first**
element (Go counts from zero), `primes[3]` the fourth - so we printed `2` then `7`. Indexing past the end
(say `primes[4]`) crashes with an out-of-range error, since there's no fifth element.

## Growing a slice with `append`

A slice's whole point is that it can grow. You do that with the built-in `append` function:
```go
package main

import "fmt"

func main() {
	names := []string{"Ada", "Alan"}
	names = append(names, "Grace")
	fmt.Println(names)
}
```
```console
$ go run main.go
[Ada Alan Grace]
```
`append(names, "Grace")` produced a slice with `"Grace"` added on the end. The surprise: **you assign the
result back to `names`.** `append` doesn't always change the original in place - it may build a bigger
slice and hand it back - so the idiom is *always* `names = append(names, ...)`. Skip the `names =` and
your addition vanishes.

You can append several at once, or even append one slice onto another:
```go
names = append(names, "Linus", "Margaret")
```
`append` takes the slice first, then any number of new values, returning the grown slice. Same rule:
capture the result.

## `len` and `cap` - length vs capacity

Two built-in functions tell you about a slice's size:
```go
package main

import "fmt"

func main() {
	s := []int{10, 20, 30}
	fmt.Println(len(s), cap(s))
}
```
```console
$ go run main.go
3 3
```
`len(s)` is the **length** - how many elements the slice holds right now (3). `cap(s)` is the
**capacity** - how many it could hold before Go must allocate a bigger block of memory. **`len` is the one
you'll use constantly**; `cap` is under-the-hood detail you'll mostly ignore until optimizing. They start
equal here, but after appends they can differ as Go grows backing storage in chunks.

## Maps - looking things up by key

A slice is great for an ordered list, accessed by *position*. A **map** is for accessing things by *name*:
a lookup table storing **key → value** pairs. `map[string]int` reads as "a map from string keys to
integer values" - names to ages, say. (Other languages call this a dictionary, hash, or associative
array; same idea.)
```go
package main

import "fmt"

func main() {
	ages := map[string]int{
		"Ada":  36,
		"Alan": 41,
	}
	fmt.Println(ages["Ada"])
	ages["Grace"] = 28
	fmt.Println(ages)
}
```
```console
$ go run main.go
36
map[Ada:36 Alan:41 Grace:28]
```
We created a map with two entries, looked up `"Ada"` to get `36`, then added an entry by assigning to a
fresh key (`ages["Grace"] = 28`). Go printed them in tidy order here (because `fmt` sorts map keys when printing), but **maps have no
guaranteed order** - ranging over a map visits keys in randomized order, so don't rely on it.

When you look up a key that might not exist, use the **two-value form** to ask "did it exist?":
```go
age, ok := ages["Nobody"]
fmt.Println(age, ok)
```
```console
0 false
```
Reading a missing key doesn't crash - it returns the value type's **zero value** (`0` for an `int`, from
[phase 2](02-syntax-values-and-types.md)) plus a boolean, `ok`, `false` when the key was absent. The
`value, ok := m[key]` pattern distinguishes "the value is genuinely 0" from "the key wasn't there at all."

⚠️ **Gotcha - writing to a nil map panics.** A map variable declared but never *made* is `nil`, and
**writing to a nil map crashes your program at runtime:**
```go
var m map[string]int   // declared, but nil - never made
m["x"] = 1             // panic!
```
```console
panic: assignment to entry in nil map
```
`var m map[string]int` gives you a `nil` map - the zero value for maps. You can *read* from it (zero
values come back), but *writing* panics, since no table is allocated to store into. Fix: create it first
with `make`: `m := make(map[string]int)` (or a map literal like above). One of the most common first-week
Go panics - now you'll recognize it instantly.

📝 **Terminology.** A **panic** is Go's term for a runtime crash - the program stops with an error message
and a trace, the runtime equivalent of an exception. Handling failure *gracefully* (the "errors are
values" approach) comes in [phase 7](07-errors-and-io.md).

## Looping over collections with `range`

To visit every element of a slice or every pair in a map, Go gives you `range`:
```go
package main

import "fmt"

func main() {
	names := []string{"Ada", "Alan", "Grace"}
	for i, name := range names {
		fmt.Println(i, name)
	}
}
```
```console
$ go run main.go
0 Ada
1 Alan
2 Grace
```
`for i, name := range names` walks the slice, handing you `i`, the **index** (starting at 0), and `name`,
the **value** at that position - the standard way to loop a slice. (Don't worry about the `for` keyword
yet - Go's single loop is [phase 4](04-control-flow-and-functions.md); here it's just "do this for each
element.")

Often you only want the value, not the index. Use the blank identifier `_` to throw the index away:
```go
for _, name := range names {
	fmt.Println(name)
}
```
`_` is Go's "I deliberately don't want this" placeholder. Since Go errors on *unused variables*
([phase 2](02-syntax-values-and-types.md)), `_` says "discard the index on purpose." Ranging a map works
the same way, giving `key, value` instead of `index, value`.

## The slice-aliasing surprise

Here's the slice gotcha that bites everyone exactly once. A slice is a *view* onto an underlying block of
data. When you slice a slice, both names can point at the *same* underlying data:
```go
package main

import "fmt"

func main() {
	original := []int{1, 2, 3, 4}
	part := original[0:2]   // a view of the first two elements
	part[0] = 99
	fmt.Println(original)
}
```
```console
$ go run main.go
[99 2 3 4]
```
`original[0:2]` made `part` a *window* onto `original`'s first two elements - not a copy. Changing
`part[0]` also changed `original[0]`; they share the same backing storage. Efficient (no copying) but
surprising the first time a slice changes "by itself."

⚠️ **Gotcha.** When you need an *independent* copy rather than a shared view, make one explicitly with the
built-in `copy`:
```go
clone := make([]int, len(original))
copy(clone, original)
```
`make([]int, len(original))` created a new slice of the same length, and `copy` filled it with
`original`'s values. Now `clone` has its own storage - changing it leaves `original` untouched. Reach for
this whenever "I changed one and the other changed too" would be a bug.

## Recap

1. **`[]T` is a slice** (flexible, what you'll use); `[N]T` is an array (fixed size, rare).
2. **`append`** grows a slice - always assign the result back: `s = append(s, x)`.
3. **`len`** is how many elements (you'll use it constantly); **`cap`** is the under-the-hood capacity.
4. A **map** (`map[K]V`) stores key→value pairs for instant lookup; use **`value, ok := m[key]`** to
   check if a key exists.
5. **Writing to a nil map panics** - create it first with `make` or a literal.
6. **`range`** loops collections, giving `index, value` for slices and `key, value` for maps; use `_` to
   discard a part you don't need.
7. Slices can **share underlying data** (aliasing) - use `copy` when you need an independent copy.

Next: making decisions and organizing logic - Go's one loop, `if` and `switch`, and the
multiple-return-value functions that give Go its distinctive shape.
