Monday, February 9, 2026

Array & Slice

    Profile Pic of Akash AmanAkash Aman

    Updated: February 2026

    Arrays

    Fixed-Length Containers ([n]T)

    Concept: An array is a numbered sequence of elements of a specific length. In Go, the size is part of the type. This means [3]int and [4]int are entirely different types and cannot be assigned to each other.

    Setup:

    go
    // Defining and initializing
    var arr1 [3]int                      // [0, 0, 0] (Zero-valued)
    arr2 := [3]int{10, 20, 30}           // Specific values
    arr3 := [...]int{1, 2, 3, 4}         // Compiler infers length (4)
    
    • Behavior: Arrays are Value Types. When you assign an array to a new variable or pass it to a function, Go creates a complete copy of the data.
    • Why: Use arrays when you need strict memory layout or when the data size is a known mathematical constant (e.g., a transformation matrix or cryptographic hash).

    Multi-Dimensional Arrays

    Concept: Arrays can be nested to create grids or matrices.

    Behavior:

    go
    // A 2x3 grid
    matrix := [2][3]int{
        {1, 2, 3},
        {4, 5, 6},
    }
    
    • Why: Useful for coordinate systems or representing structured data like a chessboard or a pixel grid where the dimensions never change.

    Slices

    The Slice Header ([]T)

    Concept: A slice is a lightweight structure (a "descriptor") that points to an underlying array. It consists of three fields: a Pointer to the data, a Length, and a Capacity.

    Setup:

    go
    // Literal declaration
    nums := []int{1, 2, 3} 
    
    // Using make (Length 5, Capacity 10)
    taskBuffer := make([]string, 5, 10) 
    
    • Behavior: Slices are Reference-like. Passing a slice to a function only copies the 24-byte header (on 64-bit systems), not the underlying data. Modifying elements inside a function affects the original caller.
    • Why: Slices are the "workhorse" of Go because they allow for flexible, dynamic collections without the overhead of copying large amounts of data.

    Length vs. Capacity

    Concept: - Length (len): The number of elements currently in the slice.

    • Capacity (cap): The number of elements in the underlying array, starting from the first element in the slice.

    Behavior:

    • When you append to a slice and exceed its capacity, Go allocates a new, larger array, copies the data, and returns a new header pointing to the new memory.
    go
    s := make([]int, 0, 3) // len=0, cap=3
    s = append(s, 1, 2)    // len=2, cap=3
    s = append(s, 3, 4)    // len=4, cap=6 (Capacity doubled to accommodate)
    
    • Why: Understanding capacity helps you optimize performance. If you know you'll need 1,000 items, using make([]T, 0, 1000) prevents dozens of unnecessary memory allocations.

    Essential Slice Operations

    The Append Function

    Concept: The built-in append adds elements to the end of a slice.

    Behavior:

    go
    prime := []int{2, 3}
    morePrimes := []int{5, 7, 11}
    
    // Appending single values
    prime = append(prime, 13)
    
    // Appending another slice (Variadic expansion)
    prime = append(prime, morePrimes...) 
    
    • Why: It handles the complex logic of checking capacity and re-allocating memory automatically, providing a simple API for dynamic growth.

    The Copy Function

    Concept: copy(dest, src) clones elements from one slice to another.

    Behavior:

    • It only copies up to the minimum of len(dest) or len(src).
    • It handles overlapping slices correctly (moving data within the same array).
    go
    src := []int{1, 2, 3}
    dst := make([]int, len(src))
    copy(dst, src) // Independent copy created
    
    • Why: Essential when you want to create a "snapshot" of data that won't change if the original underlying array is modified.

    Slicing Mechanics

    Sub-slicing (Windows)

    Concept: You can create a new slice from an existing one using slice[low:high].

    Behavior:

    go
    months := []string{"Jan", "Feb", "Mar", "Apr", "May"}
    q1 := months[0:3] // "Jan", "Feb", "Mar"
    
    • Crucial Note: q1 and months share the same memory. Changing q1[0] to "Zero" will make months[0] also "Zero".
    • Why: This is extremely efficient for processing subsets of data (like reading a specific header from a network packet) without copying bytes.

    Reference Guides

    Summary Table: Array vs. Slice

    FeatureArray ([n]T)Slice ([]T)
    SizeFixed (part of the type)Dynamic (growable)
    PassingPassed by Value (Copies all)Passed by Reference (Copies header)
    StorageContiguous memoryHeader pointing to contiguous memory
    Common UseLow-level optimization99% of general Go development

    Common Gotchas for Newbies

    ScenarioWhat happens?
    Passing Array to FunctionThe function gets a copy; changes don't persist outside.
    Append without Assignmentappend(s, val) does nothing. You must use s = append(s, val).
    Zero-Valuevar a [2]int is [0, 0]. var s []int is nil.
    Out of BoundsAccessing an index >= len causes a panic, even if it is < cap.

    © 2026 Akash Aman | All rights reserved