cannot range over em Go

O erro “cannot range over X” aparece quando você tenta usar for range com um tipo que não suporta iteração. O range do Go funciona apenas com tipos específicos, e usá-lo com qualquer outro tipo resulta em erro de compilação.


A Mensagem de Erro

./main.go:10:15: cannot range over num (variable of type int)
./main.go:12:15: cannot range over usuario (variable of type Usuario)

Tipos que Suportam range

Em Go, range funciona apenas com estes tipos:

TipoProduzExemplo
array / sliceíndice, valorfor i, v := range []int{1,2,3}
stringíndice, runefor i, r := range "Go"
mapchave, valorfor k, v := range map[string]int{}
channelvalorfor v := range ch
int (Go 1.22+)índicefor i := range 5
func(yield) (Go 1.23+)valores do yieldfor v := range iterador

Causas Comuns

1. Range sobre Tipo Numérico (antes do Go 1.22)

Antes do Go 1.22, não era possível usar range com inteiros:

package main

import "fmt"

func main() {
    // ERRO (antes do Go 1.22): cannot range over 5 (untyped int constant)
    for i := range 5 {
        fmt.Println(i)
    }
}

2. Range sobre Struct

Structs não são iteráveis por padrão:

package main

import "fmt"

type Ponto struct {
    X, Y int
}

func main() {
    p := Ponto{X: 10, Y: 20}

    // ERRO: cannot range over p (variable of type Ponto)
    for v := range p {
        fmt.Println(v)
    }
}

3. Range sobre Ponteiro para Slice

Um ponteiro para slice não é um slice:

package main

import "fmt"

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

    // ERRO: cannot range over nums (variable of type *[]int)
    for _, v := range nums {
        fmt.Println(v)
    }
}

4. Range sobre Interface Sem Tipo Concreto

Se uma interface pode ser qualquer tipo, o compilador não sabe como iterar:

package main

import "fmt"

func processar(dados interface{}) {
    // ERRO: cannot range over dados (variable of type interface{})
    for _, v := range dados {
        fmt.Println(v)
    }
}

Como Resolver

Solução 1: Range sobre Inteiro (Go 1.22+)

A partir do Go 1.22, range funciona com inteiros:

package main

import "fmt"

func main() {
    // Go 1.22+: range sobre inteiro
    for i := range 5 {
        fmt.Println(i) // 0, 1, 2, 3, 4
    }
}

Se estiver em uma versão anterior, use o loop for tradicional:

for i := 0; i < 5; i++ {
    fmt.Println(i)
}

Solução 2: Converter Struct para Slice

Para iterar sobre campos de uma struct, converta explicitamente:

package main

import "fmt"

type Ponto struct {
    X, Y, Z int
}

func (p Ponto) Coords() []int {
    return []int{p.X, p.Y, p.Z}
}

func main() {
    p := Ponto{X: 10, Y: 20, Z: 30}

    for i, v := range p.Coords() {
        fmt.Printf("coord[%d] = %d\n", i, v)
    }
}

Solução 3: Desreferenciar o Ponteiro

Para ponteiros para slices, desreferencie com *:

package main

import "fmt"

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

    // Desreferencia o ponteiro
    for _, v := range *nums {
        fmt.Println(v)
    }
}

Solução 4: Type Assertion para Interfaces

Converta a interface para o tipo concreto:

package main

import "fmt"

func processar(dados interface{}) {
    // Type assertion para slice
    if slice, ok := dados.([]int); ok {
        for _, v := range slice {
            fmt.Println(v)
        }
        return
    }

    // Type switch para múltiplos tipos
    switch d := dados.(type) {
    case []string:
        for _, v := range d {
            fmt.Println(v)
        }
    case map[string]int:
        for k, v := range d {
            fmt.Printf("%s: %d\n", k, v)
        }
    default:
        fmt.Println("tipo não suportado para iteração")
    }
}

func main() {
    processar([]int{1, 2, 3})
    processar([]string{"a", "b", "c"})
}

Solução 5: Iteradores Customizados (Go 1.23+)

A partir do Go 1.23, você pode definir iteradores customizados usando range over func. Isso é o que a comunidade chama de iteradores em Go:

package main

import (
    "fmt"
    "iter"
)

type Arvore struct {
    Valor    int
    Esquerda *Arvore
    Direita  *Arvore
}

// Iterador in-order para árvore binária
func (a *Arvore) InOrder() iter.Seq[int] {
    return func(yield func(int) bool) {
        if a == nil {
            return
        }
        for v := range a.Esquerda.InOrder() {
            if !yield(v) {
                return
            }
        }
        if !yield(a.Valor) {
            return
        }
        for v := range a.Direita.InOrder() {
            if !yield(v) {
                return
            }
        }
    }
}

func main() {
    arvore := &Arvore{
        Valor: 2,
        Esquerda: &Arvore{Valor: 1},
        Direita:  &Arvore{Valor: 3},
    }

    // Usa range com iterador customizado
    for v := range arvore.InOrder() {
        fmt.Println(v) // 1, 2, 3
    }
}

Solução 6: Usar Generics para Iteração

Com generics, crie funções de iteração reutilizáveis:

package main

import "fmt"

func Filtrar[T any](items []T, pred func(T) bool) []T {
    var resultado []T
    for _, item := range items {
        if pred(item) {
            resultado = append(resultado, item)
        }
    }
    return resultado
}

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

    pares := Filtrar(nums, func(n int) bool {
        return n%2 == 0
    })

    for _, v := range pares {
        fmt.Println(v) // 2, 4, 6, 8, 10
    }
}

Dicas para Evitar Este Erro

  1. Conheça os tipos iteráveis — slices, arrays, maps, strings, channels e (Go 1.22+) inteiros.

  2. Atualize para Go 1.22+range sobre inteiros simplifica muitos loops. Veja como instalar Go.

  3. Explore iteradores — o Go 1.23 introduziu range over func, revolucionando a iteração customizada. Leia sobre iteradores em Go.

  4. Prefira slices a ponteiros de slices — passar slices por valor já é eficiente (slices são referências internas).

  5. Use generics — para funções genéricas de iteração. Veja generics no Go 1.18.


Erros Relacionados