HowtoGo
Data Structures

Slices

A slice is a growable view over an array, the sequence type Go reaches for by default. Slices can hold any type of data and can be resized. You can have a byte slice []byte, a string slice []string, or a slice of structs []MyStruct. Slices are the most common way to work with collections of data in Go.

Examples

A slice literal skips the length an array literal needs. The length isn't part of a slice's type.

s := []int{1, 2, 3}
fmt.Println(s, len(s))
Output
[1 2 3] 3

Did you know?

The standard library's slices package isn't built from anything special. Almost all the functions in the package can be engineered using the same primitives available in any Go program - range, indexing, append, copy and so on. The below examples are pretty close to what the Standard Library provides.

This is what slices.Contains does: Loop, Compare, Return.

func contains[S ~[]E, E comparable](s S, v E) bool {
    for _, x := range s {
        if x == v {
            return true
        }
    }
    return false
}

slices.Reverse is exactly this: two indices closing in from both ends, swapping as they go.

func reverse[S ~[]E, E any](s S) {
    for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {
        s[i], s[j] = s[j], s[i]
    }
}

append(s[:i], s[j:]...) shifts everything after the deleted range left, over the gap. clear zeroes the leftover tail so those values don't keep anything alive for the garbage collector.

func deleteAt[S ~[]E, E any](s S, i, j int) S {
    oldlen := len(s)
    s = append(s[:i], s[j:]...)
    clear(s[len(s):oldlen]) // let GC reclaim what's left over
    return s
}

Each hand-written version runs next to its slices counterpart on the same input.

package main

import (
    "fmt"
    "slices"
)

// contains, reverse, and deleteAt as above

func main() {
    a := []int{1, 2, 3, 4, 5}
    fmt.Println(contains(a, 3), slices.Contains(a, 3))

    b := slices.Clone(a)
    reverse(a)
    slices.Reverse(b)
    fmt.Println(a, b)

    c := deleteAt(slices.Clone(a), 1, 3)
    d := slices.Delete(slices.Clone(b), 1, 3)
    fmt.Println(c, d)
}

Identical output both ways. The stdlib functions aren't doing anything a Go program couldn't write itself.

Terminal
$ go run built.go
true true
[5 4 3 2 1] [5 4 3 2 1]
[5 2 1] [5 2 1]