beginner Step 5 of 15

Arrays, Slices, and Maps

Go Programming

Arrays, Slices, and Maps

Go provides three primary collection types: arrays (fixed-size), slices (dynamic-size views of arrays), and maps (key-value pairs). Slices are by far the most commonly used — they provide the flexibility of dynamic arrays with excellent performance. Maps are Go's built-in hash table implementation. Understanding the difference between arrays and slices, how slices reference underlying arrays, and the behavior of maps is essential for writing correct and efficient Go code.

Slices

package main

import "fmt"

func main() {
    // Create slices
    fruits := []string{"apple", "banana", "cherry"}
    numbers := make([]int, 5)       // length 5, all zeros
    buffer := make([]byte, 0, 100)  // length 0, capacity 100

    // Append (may allocate new underlying array)
    fruits = append(fruits, "date")
    fruits = append(fruits, "elderberry", "fig")

    // Slicing
    subset := fruits[1:3]   // ["banana", "cherry"]
    first3 := fruits[:3]
    last2 := fruits[len(fruits)-2:]

    // Length and capacity
    fmt.Println(len(fruits), cap(fruits))

    // Iterating
    for i, fruit := range fruits {
        fmt.Printf("%d: %s\n", i, fruit)
    }

    // Copy
    src := []int{1, 2, 3, 4, 5}
    dst := make([]int, len(src))
    copy(dst, src)

    // Delete element at index
    i := 2
    fruits = append(fruits[:i], fruits[i+1:]...)

    // Filter pattern
    var evens []int
    for _, n := range []int{1, 2, 3, 4, 5, 6, 7, 8} {
        if n%2 == 0 {
            evens = append(evens, n)
        }
    }
    fmt.Println(evens)  // [2 4 6 8]

    fmt.Println(subset, first3, last2, numbers, buffer)
}

Maps

// Create maps
scores := map[string]int{
    "Alice":   95,
    "Bob":     87,
    "Charlie": 92,
}

// Or with make
userRoles := make(map[int]string)
userRoles[1] = "admin"
userRoles[2] = "user"

// Access
fmt.Println(scores["Alice"])  // 95

// Check existence (comma ok idiom)
score, exists := scores["Diana"]
if !exists {
    fmt.Println("Diana not found")
}

// Delete
delete(scores, "Bob")

// Iterate (order is NOT guaranteed)
for name, score := range scores {
    fmt.Printf("%s: %d\n", name, score)
}

// Map of slices
groups := map[string][]string{
    "fruits":     {"apple", "banana"},
    "vegetables": {"carrot", "pea"},
}
groups["fruits"] = append(groups["fruits"], "cherry")

// Length
fmt.Println(len(scores))
Pro tip: When checking if a key exists in a map, always use the comma-ok idiom: value, ok := myMap[key]. Simply reading myMap[key] returns the zero value if the key does not exist, which can be indistinguishable from a key that exists with a zero value.

Key Takeaways

  • Slices are dynamic, reference underlying arrays, and are the go-to collection type in Go.
  • Use append() to add elements and copy() to duplicate slices safely.
  • Maps provide O(1) key-value lookups; use the comma-ok idiom (v, ok := m[k]) to check existence.
  • Map iteration order is randomized by design — do not rely on insertion order.
  • Use make() to create slices and maps with initial capacity for better performance.