Learn › Go Programming

Arrays, Slices & Maps

Work with Go's fundamental collection types: fixed-size arrays, dynamic slices, and hash maps.

Arrays

Arrays in Go are fixed-size sequences of elements of the same type, where the size is part of the type itself. This means [5]int and [10]int are different types and cannot be assigned to each other. Arrays are value types in Go, so assigning an array to another variable copies all elements. Because of their fixed size, arrays are rarely used directly in Go — slices are preferred for most use cases.

package main

import "fmt"

func main() {
    // Declare and initialize
    var numbers [5]int
    numbers[0] = 10
    numbers[1] = 20

    // Array literal
    primes := [5]int{2, 3, 5, 7, 11}

    // Compiler counts elements
    vowels := [...]string{"a", "e", "i", "o", "u"}

    fmt.Println("numbers:", numbers)
    fmt.Println("primes:", primes)
    fmt.Println("vowels:", vowels)
    fmt.Println("length:", len(primes))

    // Arrays are value types (copied on assignment)
    original := [3]int{1, 2, 3}
    copy := original
    copy[0] = 99
    fmt.Println("original:", original) // [1 2 3]
    fmt.Println("copy:", copy)         // [99 2 3]
}

Slices

Slices are the workhorse collection type in Go, providing a flexible, dynamic view into an underlying array. Unlike arrays, slices have a dynamic length and are reference types, meaning they point to the same underlying data when assigned or passed to functions. A slice has three components: a pointer to the underlying array, a length, and a capacity. You can create slices using literals, the 'make' function, or by slicing an existing array or slice.

package main

import "fmt"

func main() {
    // Slice literal
    fruits := []string{"apple", "banana", "cherry"}

    // Create with make(type, length, capacity)
    scores := make([]int, 3, 10)
    scores[0] = 90
    scores[1] = 85
    scores[2] = 92

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

    // Slicing
    fmt.Println(fruits[1:3]) // [banana cherry]
    fmt.Println(fruits[:2])  // [apple banana]
    fmt.Println(fruits[3:])  // [date elderberry]

    fmt.Printf("len=%d cap=%d %v\n", len(scores), cap(scores), scores)

    // Copy slices
    src := []int{1, 2, 3}
    dst := make([]int, len(src))
    copied := copy(dst, src)
    fmt.Printf("Copied %d elements: %v\n", copied, dst)
}

Maps

Maps in Go are hash tables that store key-value pairs with O(1) average lookup time. Maps must be initialized before use, either with a map literal or the 'make' function — a nil map will panic on write operations. The comma-ok idiom lets you distinguish between a missing key and a zero value. Maps are not safe for concurrent access; you need sync.Mutex or sync.Map for concurrent scenarios.

package main

import "fmt"

func main() {
    // Map literal
    colors := map[string]string{
        "red":   "#ff0000",
        "green": "#00ff00",
        "blue":  "#0000ff",
    }

    // Create with make
    scores := make(map[string]int)
    scores["Alice"] = 95
    scores["Bob"] = 87

    // Access and check existence
    hex := colors["red"]
    fmt.Println("Red:", hex)

    // Comma-ok idiom
    value, exists := colors["purple"]
    if !exists {
        fmt.Println("purple not found, got zero value:", value)
    }

    // Delete a key
    delete(scores, "Bob")

    // Iterate over a map
    for key, val := range colors {
        fmt.Printf("%s -> %s\n", key, val)
    }

    fmt.Println("Map length:", len(colors))
}

Iteration Patterns

Go provides consistent iteration patterns across its collection types using the 'range' keyword. When ranging over slices, you get the index and a copy of the element at that index. For maps, you get the key and value. If you only need the index or key, you can omit the second variable. If you only need the value, use the blank identifier '_' for the index to avoid compiler errors about unused variables.

package main

import (
    "fmt"
    "sort"
)

func main() {
    names := []string{"Charlie", "Alice", "Bob"}

    // Sort a slice
    sort.Strings(names)
    fmt.Println("Sorted:", names)

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

    // Map transformation pattern
    words := []string{"hello", "world", "go"}
    lengths := make(map[string]int)
    for _, w := range words {
        lengths[w] = len(w)
    }
    fmt.Println("Lengths:", lengths)

    // Iterating with index only
    for i := range names {
        fmt.Printf("Index %d: %s\n", i, names[i])
    }
}

← Control Flow · Structs & Interfaces →