ZetCode

Golang slices.Chunk

last modified June 21, 2026

This tutorial explains how to use the slices.Chunk function in Go. We cover iterating over successive non-overlapping chunks of a slice with practical examples.

The slices.Chunk function returns an iterator (iter.Seq[S]) that yields successive non-overlapping sub-slices of length n. Its signature is:

func Chunk[Slice ~[]E, E any](s Slice, n int) iter.Seq[Slice]

The function was introduced in Go 1.23. Every chunk except possibly the last has exactly n elements. The chunks are sub-slices of the original, so they share the same backing array.

Basic slices.Chunk Example

The simplest use iterates over chunks with a for range loop. Here we split a slice of six integers into chunks of size 2.

basic_chunk.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    numbers := []int{1, 2, 3, 4, 5, 6}

    for chunk := range slices.Chunk(numbers, 2) {
        fmt.Println(chunk)
    }
}

The iterator yields each sub-slice in order. Because the length (6) is evenly divisible by the chunk size (2), all three chunks have equal length.

Uneven Chunk Sizes

When the slice length is not evenly divisible by the chunk size, the last chunk contains the remaining elements.

uneven_chunks.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    letters := []string{"a", "b", "c", "d", "e"}

    for chunk := range slices.Chunk(letters, 2) {
        fmt.Printf("chunk: %v\n", chunk)
    }
}

Five elements chunked by 2 produce two full chunks and one remainder chunk of length 1.

Collecting All Chunks into a Slice

When you need all chunks at once — for example to index into them — use slices.Collect to materialise the iterator into a [][]E.

collect_chunks.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    data := []int{10, 20, 30, 40, 50, 60, 70}

    chunks := slices.Collect(slices.Chunk(data, 3))

    fmt.Println("number of chunks:", len(chunks))
    fmt.Println("first chunk:     ", chunks[0])
    fmt.Println("last chunk:      ", chunks[len(chunks)-1])
}

slices.Collect drains the iterator and returns a [][]int. The last chunk has only one element because 7 is not divisible by 3.

Chunk Size Larger Than the Slice

If the chunk size is equal to or greater than the slice length, the iterator yields exactly one chunk containing all elements.

large_chunk.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    data := []float64{1.1, 2.2, 3.3}

    for chunk := range slices.Chunk(data, 10) {
        fmt.Println(chunk) // [1.1 2.2 3.3]
    }
}

A chunk size of 10 is larger than the three-element slice, so the loop body executes once with the entire slice as the single chunk.

Working with Structs

slices.Chunk works with any element type, including custom structs.

struct_chunk.go
package main

import (
    "fmt"
    "slices"
)

type Person struct {
    Name string
    Age  int
}

func main() {
    people := []Person{
        {"Alice", 25},
        {"Bob", 30},
        {"Charlie", 17},
        {"Diana", 22},
        {"Eve", 28},
    }

    i := 1
    for chunk := range slices.Chunk(people, 2) {
        fmt.Printf("group %d:\n", i)
        for _, p := range chunk {
            fmt.Printf("  %s (%d)\n", p.Name, p.Age)
        }
        i++
    }
}

Each chunk is a sub-slice of the original people slice. The struct values are not copied beyond the sub-slice header.

group 1:
  Alice (25)
  Bob (30)
group 2:
  Charlie (17)
  Diana (22)
group 3:
  Eve (28)

Chunks Share the Backing Array

Because chunks are sub-slices, modifying an element inside a chunk modifies the original slice. This is worth keeping in mind when processing chunks concurrently or after the fact.

shared_backing.go
package main

import (
    "fmt"
    "slices"
)

func main() {
    nums := []int{1, 2, 3, 4, 5, 6}

    for chunk := range slices.Chunk(nums, 2) {
        chunk[0] = 0 // modifies the original slice
    }

    fmt.Println(nums) // [0 2 0 4 0 6]
}

Setting the first element of each chunk to zero also zeroes every other element of the original slice, confirming the shared backing array.

Practical Example: Batch Processing

A common use-case is processing a large dataset in fixed-size batches to limit memory pressure or API call size.

batch_processing.go
package main

import (
    "fmt"
    "slices"
)

func insertBatch(batch []int) {
    fmt.Printf("inserting %d records: %v\n", len(batch), batch)
}

func main() {
    records := make([]int, 10)
    for i := range records {
        records[i] = (i + 1) * 10
    }

    const batchSize = 3

    for batch := range slices.Chunk(records, batchSize) {
        insertBatch(batch)
    }
}

The insertBatch function simulates inserting a batch of records into a database or an external system.

The iterator produces batches on demand, so only one chunk is in play at a time. No up-front allocation of a slice-of-slices is needed.

Source

Go slices.Chunk documentation

This tutorial covered the slices.Chunk function in Go with examples showing basic iteration, uneven sizes, collecting chunks, struct slices, shared backing arrays, and batch processing.

Author

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Go tutorials.