BudiBadu Logo

Samplebadu

Code with Example
BudiBadu Logo
Samplebadu

Go by Example: Slices

Go 1.23

Slices are the most common way to work with sequences of data in Go. Unlike arrays, they are dynamic. This example explains length vs. capacity, the `append` function, and how slices are actually "windows" into underlying arrays.

Code

package main

import "fmt"

func main() {
    // 1. Creating Slices
    // Using make(type, length, capacity)
    // Length: number of elements accessible
    // Capacity: space in underlying array
    s := make([]string, 3)
    fmt.Println("Empty slice:", s)
    fmt.Printf("Len: %d, Cap: %d\n", len(s), cap(s))

    // 2. Setting Values
    s[0] = "a"
    s[1] = "b"
    s[2] = "c"
    fmt.Println("Set:", s)

    // 3. Appending
    // append() returns a new slice (may point to new memory)
    s = append(s, "d")
    s = append(s, "e", "f")
    fmt.Println("Appended:", s)
    fmt.Printf("Len: %d, Cap: %d\n", len(s), cap(s))

    // 4. Slicing (The "Window" Concept)
    // slice[low:high] (high is exclusive)
    l := s[2:5]
    fmt.Println("Slice s[2:5]:", l)

    // 5. Copying
    // copy(dst, src) copies min(len(dst), len(src)) elements
    c := make([]string, len(s))
    copy(c, s)
    fmt.Println("Copy:", c)

    // 6. Slice Literal
    t := []string{"g", "h", "i"}
    fmt.Println("Literal:", t)
}

Explanation

In the Go programming language, slices represent a sophisticated, dynamic abstraction over standard arrays, providing a flexible and efficient mechanism for managing sequences of typed data. Unlike fixed-size arrays, slices are composite data structures that act as a "window" or descriptor for an underlying backing array, encapsulating a pointer to the memory block, the current length of the segment, and the total capacity available for expansion. This architecture allows for efficient memory manipulation and lightweight passing of data references without the performance overhead associated with copying entire data structures.

The built-in append function exemplifies the dynamic nature of slices by automatically managing memory allocation; when a slice exceeds its current capacity, the runtime seamlessly allocates a larger contiguous memory block and copies existing elements, thereby abstracting complex memory management tasks from the developer. This behavior ensures that slices remain performant while offering the convenience of dynamic resizing, although developers must remain cognizant of the underlying memory mechanics to avoid inadvertent side effects when multiple slices reference the same backing array.

  • Dynamic: Can grow using append.
  • Reference: Slicing s[i:j] creates a new view of the same array.
  • Length vs Capacity: len() is current size, cap() is max size before reallocation.
  • Zero Value: The zero value of a slice is nil.

Code Breakdown

10
Creating a slice with 'make'. We ask for a slice of strings with length 3. The capacity defaults to the length if not specified. The elements are initialized to the zero value ("").
22
The 'append' function. Note that we must assign the result back to 's' (s = append(s, ...)). This is because if the underlying array is full, 'append' returns a pointer to a NEW array location.
29
Slicing syntax. 's[2:5]' creates a new slice including elements at indices 2, 3, and 4 (but not 5). Crucially, this new slice shares the same underlying memory as 's'. Modifying 'l' would affect 's'.
35
The 'copy' function. It copies data from 's' to 'c'. It only copies as many elements as fit in the destination slice 'c'. This is how you create a truly independent copy of the data.