Chapter 07: Arrays & Slices
"Data without structure is just sand."
In the previous chapter (Loops), we learned how to process items one by one. But where do we store these items? We need containers. In Go, there are two types: the Rigid Box (Array) and the Magic Bag (Slice).
7.1 The Egg Carton (Array)
An Array is a fixed-size container.
- Rule: When you buy an egg carton for 12 eggs, it always has 12 slots. You cannot magically stretch it to hold 13.
- Syntax:
[3]int(An array of exactly 3 integers).
go
var carton [3]string
carton[0] = "Egg 1"
carton[1] = "Egg 2"
carton[2] = "Egg 3"
// carton[3] = "Egg 4" // ERROR! Out of bounds.7.2 The Magic Bag (Slice)
A Slice is a window into an underlying array. It can grow and shrink.
- Rule: If you need more space, Go automatically buys a bigger bag and moves your stuff there.
- Syntax:
[]int(Note: No number inside[]).
go
var backpack []string
backpack = append(backpack, "Flashlight")
backpack = append(backpack, "Water")Anatomy of a Slice
A slice is actually a small structure with 3 fields:
- Pointer: Where the data starts in memory.
- Length (
len): How many items are in the bag right now. - Capacity (
cap): How many elements can be reached from this slice’s starting position within its allowed capacity. This can be smaller than the whole underlying array.
7.3 Common Operations
Creating
go
// Empty slice
var list []int
// Slice with initial values
numbers := []int{1, 2, 3}
// Slice with specific size (make)
// "Give me a slice of size 5"
fiveZeros := make([]int, 5)Accessing
go
fmt.Println(numbers[0]) // First item
fmt.Println(numbers[len(numbers)-1]) // Last itemCheck len(numbers) > 0 before accessing either end of a possibly empty slice. Copying a slice does not copy its elements into independent storage.
Slicing a Slice (Inception)
You can take a piece of a slice using the [start:end] syntax.
go
// Index: 0 1 2 3 4
nums := []int{10, 20, 30, 40, 50}
// Take items from index 1 up to (but not including) 3
subset := nums[1:3] // Elements: 20, 30; shares storage with nums7.4 Practice: The Book List
In our shop, we need to store a list of books. Since we don't know how many books we'll have, we use a Slice.
go
package main
import (
"html/template"
"log"
"net/http"
)
// Lesson 3: Data (The Brain)
// Goal: Display dynamic data using Structs (Boxes) and Slices (Shelves).
// 1. The Box (Struct)
// Why Struct? It lets us group related data (Title + Price) into a single object.
type Book struct {
Title string
Author string
Price float64 // Why float64? Legacy display-only example: approximate binary floating point; use integer minor units and currency for money calculations.
}
// 2. The Shelf (Slice)
// Why Slice? Arrays are fixed size (e.g., [5]int). Slices can grow as we add books.
var books = []Book{
{"The Go Gopher", "Rob Pike", 25.00},
{"Concurrency in Go", "Katherine Cox-Buday", 30.00},
}
const htmlTmpl = `
<!DOCTYPE html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body class="container py-5">
<h1>📚 The Gopher Shop</h1>
<!-- 3. The Conveyor Belt (Range Loop) -->
<ul class="list-group mt-4">
{{range .}}
<li class="list-group-item">
<strong>{{.Title}}</strong> by {{.Author}} - ${{.Price}}
</li>
{{end}}
</ul>
</body>
</html>
`
func main() {
tmpl, _ := template.New("index").Parse(htmlTmpl)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// Pass the "Shelf" (books) to the template
tmpl.Execute(w, books)
})
log.Println("🚀 Shop v3 running on http://localhost:8080")
http.ListenAndServe(":8080", nil)
}🎓 Knowledge Check: What is the difference between a Struct and a Slice?
Answer:
- Struct (The Box): defined shape, mixed types (Name: string, Price: int).
- Slice (The Shelf): growable list, same type (List of Books).
