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:
| Tipo | Produz | Exemplo |
|---|---|---|
array / slice | índice, valor | for i, v := range []int{1,2,3} |
string | índice, rune | for i, r := range "Go" |
map | chave, valor | for k, v := range map[string]int{} |
channel | valor | for v := range ch |
int (Go 1.22+) | índice | for i := range 5 |
func(yield) (Go 1.23+) | valores do yield | for 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
Conheça os tipos iteráveis — slices, arrays, maps, strings, channels e (Go 1.22+) inteiros.
Atualize para Go 1.22+ —
rangesobre inteiros simplifica muitos loops. Veja como instalar Go.Explore iteradores — o Go 1.23 introduziu
range over func, revolucionando a iteração customizada. Leia sobre iteradores em Go.Prefira slices a ponteiros de slices — passar slices por valor já é eficiente (slices são referências internas).
Use generics — para funções genéricas de iteração. Veja generics no Go 1.18.
Erros Relacionados
- declared and not used — variáveis de range não usadas
- cannot use X as type Y — problemas de tipo ao iterar
- Iteradores em Go — range over func no Go 1.23
- Go para Iniciantes — fundamentos de loops e iteração