# Slices

Course: [Go](https://www.devtutorials.ai/learn/go) · Section: Collections
Source: https://www.devtutorials.ai/learn/go/collections/slices

> Go slices: growable lists built on arrays. Create them, append, copy, len and cap, the underlying array, slicing, removing and inserting, and arrays vs slices.

## What Are Slices?

**Slice** = a list of values of one type that can **grow and shrink**.

- It looks like an array, but without a size in the brackets: `[]int`.
- You can add items with `append`.
- Behind every slice, Go keeps an array to hold the values.

Slices are the list you will use most in Go.

**Simple lesson:** a slice is a flexible list that grows when you add items.

### A Real-World Example

Think of the class library's issue register.

- On Monday, 3 students borrow books. The list has 3 names.
- On Tuesday, 2 more borrow. The list grows to 5.
- When the page is full, the librarian moves to a **bigger page** and copies the names across.

Now the mapping:

- **The list of names** = the slice.
- **How many names are written** = the slice's **length**.
- **How many lines the page has** = the slice's **capacity**.
- **Moving to a bigger page** = Go making a new, bigger array when the old one is full.

You met arrays in **Arrays**.

- An **array** has a fixed size: `[5]int`.
- A **slice** can grow: `[]int`.
- A slice is a small window onto an array.

## What You Will Learn

In this lesson, you will learn:

1. What slices are, why they are used, and how to create them.
2. How to use `append`, `copy`, `len` and `cap`.
3. What length, capacity and the underlying array are.
4. How to slice, reslice, remove and insert elements.
5. The differences between arrays and slices, and when to use each.

## Slice Fundamentals

### Why Slices Are Used

- **The size is not known** in advance: students joining a club, marks typed in.
- **The list grows** while the program runs.
- **Functions** can take a slice of any length.
- Most Go packages give and take slices, like `strings.Split`.

### Slice Literals

**Slice literal** = a slice written out with its values.

```go runnable title="A slice literal"
package main

import "fmt"

func main() {
	marks := []int{91, 78, 85}
	names := []string{"Asha", "Ravi"}
	fmt.Println(marks, len(marks))
	fmt.Println(names, len(names))
}
```

```text
[91 78 85] 3
[Asha Ravi] 2
```

- `[]int` has **no number** inside the brackets. That makes it a slice.
- `[3]int` would be an array.

### Creating Slices

```go runnable title="make and nil slices"
package main

import "fmt"

func main() {
	a := make([]int, 3)
	b := make([]int, 0, 10)
	var c []int
	fmt.Println(a, len(a), cap(a))
	fmt.Println(b, len(b), cap(b))
	fmt.Println(c, len(c), c == nil)
}
```

```text
[0 0 0] 3 3
[] 0 10
[] 0 true
```

- `make([]int, 3)` gives three zeros, ready to use.
- `make([]int, 0, 10)` is empty, but has room for 10 without growing.
- A nil slice prints as `[]` and has length 0.

**Simple lesson:** write `[]T{...}` or use `make` to create a slice. With no number in the brackets, it is a slice, not an array.

## Working with Slices

### append()

**append** = add values to the end of a slice. It **returns** the new slice.

```go runnable title="append"
package main

import "fmt"

func main() {
	var club []string
	club = append(club, "Asha")
	club = append(club, "Ravi", "Meena")
	more := []string{"Kabir", "Priya"}
	club = append(club, more...)
	fmt.Println(club, len(club))
}
```

```text
[Asha Ravi Meena Kabir Priya] 5
```

- Always write `club = append(club, ...)`. The result must be stored.
- You can add many values at once.
- `more...` adds every element of another slice.

### len() and cap()

- **`len(s)`** = how many elements the slice has now.
- **`cap(s)`** = how many elements fit in the array behind it, before Go must make a bigger one.

Press **append** again and again. Watch the blue boxes and the dashed ones.

Look at what happens when the slice is full:

- **len = cap:** there is no room.
- Go makes a **new array**, usually about **twice** as big, and copies the values.
- So `cap` jumps: 1, 2, 4, 8, 16.

```go runnable title="Watch the capacity grow"
package main

import "fmt"

func main() {
	var s []int
	for i := 1; i <= 5; i++ {
		s = append(s, i*10)
		fmt.Println(s, "len", len(s), "cap", cap(s))
	}
}
```

```text
[10] len 1 cap 1
[10 20] len 2 cap 2
[10 20 30] len 3 cap 4
[10 20 30 40] len 4 cap 4
[10 20 30 40 50] len 5 cap 8
```

- The exact growth is chosen by Go, and it may change between versions.
- Do not write code that depends on the exact capacity.

`append` on a **nil** slice is fine: it makes the array for you.

But reading `s[0]` on an empty or nil slice is a panic. Check `len(s) > 0` first.

### copy()

**copy** = copy elements from one slice into another. It returns how many it copied.

```go runnable title="copy"
package main

import "fmt"

func main() {
	original := []int{91, 78, 85}
	backup := make([]int, len(original))
	n := copy(backup, original)
	backup[0] = 0
	fmt.Println(original, backup, n)
}
```

```text
[91 78 85] [0 78 85] 3
```

- `copy(destination, source)`: the target comes first.
- It copies only as many as fit in the smaller slice.
- `backup` has its own array now, so changing it does not change `original`.

**Simple lesson:** `append` adds and returns a new slice, `copy` makes a separate copy, and `len` and `cap` tell you size and room.

## Slice Internals

### What a Slice Really Is

A slice is a small **header** with three parts:

- **pointer** = where its first element is in the array
- **length** = how many elements you can use
- **capacity** = how many elements fit, from the start to the end of the array

### Underlying Array

**Underlying array** = the array that really holds a slice's values.

Two slices can share one underlying array.
Move the sliders, then press `part[0]++`.

Look at two things:

- **The blue boxes** are the part of the array that `part` can see.
- **Changing `part[0]`** changes the same box in `nums`.

```go runnable title="Two slices share one array"
package main

import "fmt"

func main() {
	nums := []int{10, 20, 30, 40, 50}
	part := nums[1:3]
	part[0] = 99
	fmt.Println(nums)
	fmt.Println(part, len(part), cap(part))
}
```

```text
[10 99 30 40 50]
[99 30] 2 4
```

- `part` starts at `nums[1]`, so `part[0]` is the same box as `nums[1]`.
- Its capacity is 4: from `nums[1]` to the end of the array.

### When append Surprises You

- When a slice shares an array and has spare capacity, `append` writes into that array.
- To keep them apart, make a real copy first with `copy`.

**Simple lesson:** a slice is a window onto an array, and slices that share an array share their changes.

## Slice Operations

### Slicing

**Slicing** = taking part of a slice or array: `s[low:high]`.

- `low` is included. `high` is not.
- `s[:3]` = from the start up to 3.
- `s[2:]` = from 2 to the end.
- `s[:]` = all of it.

```go runnable title="Slicing"
package main

import "fmt"

func main() {
	days := []string{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}
	fmt.Println(days[1:4])
	fmt.Println(days[:2])
	fmt.Println(days[4:])
}
```

```text
[Tue Wed Thu]
[Mon Tue]
[Fri Sat]
```

### Reslicing

**Reslicing** = slicing a slice again. It is fast, because no values are copied.

```go runnable title="Reslice to drop the first and last"
package main

import "fmt"

func main() {
	queue := []string{"Asha", "Ravi", "Meena", "Kabir"}
	queue = queue[1:]
	fmt.Println(queue)
	queue = queue[:len(queue)-1]
	fmt.Println(queue)
}
```

```text
[Ravi Meena Kabir]
[Ravi Meena]
```

- `queue[1:]` drops the first element, like serving the first person in a line.
- `queue[:len(queue)-1]` drops the last element.

### Removing Elements

To remove the element at index `i`, join the parts before and after it.

```go runnable title="Remove an element"
package main

import "fmt"

func main() {
	names := []string{"Asha", "Ravi", "Meena", "Kabir"}
	i := 1
	names = append(names[:i], names[i+1:]...)
	fmt.Println(names, len(names))
}
```

```text
[Asha Meena Kabir] 3
```

- `names[:i]` = everything before index 1.
- `names[i+1:]...` = everything after it.
- `append` joins them, so `"Ravi"` is gone.

### Inserting Elements

To put a value at index `i`, make room and move the rest right.

```go runnable title="Insert an element"
package main

import "fmt"

func main() {
	line := []string{"Asha", "Meena", "Kabir"}
	i := 1
	line = append(line, "")
	copy(line[i+1:], line[i:])
	line[i] = "Ravi"
	fmt.Println(line)
}
```

```text
[Asha Ravi Meena Kabir]
```

- `append(line, "")` adds one empty slot at the end.
- `copy` moves everything from `i` one step to the right.
- Then we put `"Ravi"` into the free slot.

**Easy way to remember**

- Remove at `i`: `s = append(s[:i], s[i+1:]...)`
- Insert at `i`: grow by one, `copy(s[i+1:], s[i:])`, then `s[i] = v`
- Go 1.21+ also has `slices.Delete` and `slices.Insert`. This lab does not run the `slices` package.

**Simple lesson:** `s[low:high]` takes a part, and `append` with slicing removes or inserts elements.

## Arrays vs Slices

### Differences

| | Array | Slice |
|---|---|---|
| Written as | `[5]int` | `[]int` |
| Size | Fixed, part of the type | Can grow with `append` |
| Assigning `b := a` | Copies every element | Copies the header. Both share the array |
| Passing to a function | The function gets a copy | The function can change the elements |
| Compare with `==` | Yes | No, only with `nil` |
| Zero value | Full of zero values | `nil` |

### Memory Behavior

```go runnable title="A function can change a slice's elements"
package main

import "fmt"

func addGrace(marks []int) {
	for i := range marks {
		marks[i] += 5
	}
}

func main() {
	marks := []int{40, 60, 80}
	addGrace(marks)
	fmt.Println(marks)
}
```

```text
[45 65 85]
```

- The function gets a copy of the **header**, but both headers point to the **same array**.
- So the changes are seen by the caller.
- With an array, the function would change only its own copy. See **Arrays**.

### When to Use Each

- **Use a slice** almost always: lists of students, marks, words, lines of a file.
- **Use an array** when the size is truly fixed and small: the 7 days of a week, an RGB colour `[3]uint8`.
- **Use an array** when you need to compare with `==` or use it as a map key.

**Simple lesson:** use slices for lists that change, and arrays only for small, fixed-size groups.

## TL;DR

1. **Slice** = a growable list: `[]int`. An array holds its values.
2. **Create** = `[]int{1, 2}`, `make([]int, len, cap)`, `var s []int` (nil), `arr[1:3]`.
3. **append** = `s = append(s, v)`. Always store the result.
   - `append(s, other...)` adds a whole slice.
4. **len** = elements in use. **cap** = room in the array.
   - Full → Go makes a bigger array (often double).
5. **copy(dst, src)** = a separate copy.
6. **Slicing** = `s[low:high]`, low included, high not. It shares the array.
7. **Remove** = `append(s[:i], s[i+1:]...)`. **Insert** = grow, `copy`, set.
8. **Array vs slice** = fixed and copied vs growable and shared.

## Common mistakes

| Mistake | Wrong idea | Correct idea | What goes wrong |
|---|---|---|---|
| `append(s, 5)` without `s =` | `append` changes `s` in place | It returns the new slice | The new value is lost. |
| `b := a` to make a backup | It copies the values | It shares the array | Changing `b` changes `a`. Use `copy`. |
| `s[len(s)]` | The last index is `len` | It is `len - 1` | `index out of range` |
| `s[2:5]` on a 4-element slice | Slicing past the end is fine | `high` must be ≤ `cap` | `slice bounds out of range` |
| Writing to `make([]int, 0, 5)[0]` | `cap` gives usable boxes | Only `len` boxes are usable | `index out of range` |
| `a == b` for two slices | Slices compare like arrays | Only `== nil` is allowed | A build error. |
| Depending on exact `cap` growth | Growth is always ×2 | Go chooses, and it may change | Code breaks on another version. |

## Check Yourself

## Exercises

## What to Remember

- A slice is a growable list: `[]T`. An array holds its values.
- Always write `s = append(s, ...)`.
- `len` is what you use. `cap` is the room before Go must grow the array.
- `s[low:high]` shares the array. Use `copy` for a separate copy.
- Remove with `append(s[:i], s[i+1:]...)`.
- Use slices for most lists. Use arrays only for small, fixed groups.

Next: **Maps**. You will learn how to store values by a key, like marks by student name.
