---
title: "Iterator Pattern em Zig — O que é e Como Usar"
url: "https://ziglang.com.br/glossario/iterator-pattern-em-zig-o-que-%C3%A9-e-como-usar/"
markdown_url: "https://ziglang.com.br/glossario/iterator-pattern-em-zig-o-que-%C3%A9-e-como-usar.MD"
description: "Entenda o padrão Iterator em Zig: iteração preguiçosa sobre sequências usando a convenção next() que retorna optional. Guia pt-BR."
date: "2026-02-21"
author: "Zig Brasil"
---

# Iterator Pattern em Zig — O que é e Como Usar

Entenda o padrão Iterator em Zig: iteração preguiçosa sobre sequências usando a convenção next() que retorna optional. Guia pt-BR.


# Iterator Pattern em Zig — O que é e Como Usar

## Definição

O **Iterator Pattern** (padrão de iteração) em Zig segue a convenção de expor um método `next()` que retorna `?T` — ou seja, um [optional](/glossario/optional/) que é `null` quando a iteração termina. Diferente de linguagens com traits/interfaces formais de iterador (como Rust ou Java), Zig usa duck typing via `anytype` ou convenção explícita. Qualquer struct com um método `next()` que retorne optional pode ser usada como iterador.

Este padrão é usado extensivamente na biblioteca padrão para tokenização de strings, iteração sobre diretórios, leitura de linhas e muito mais.

## Por que Iterator Pattern Importa

1. **Avaliação preguiçosa**: Dados são produzidos sob demanda, sem alocar tudo na memória.
2. **Composição**: Iteradores podem ser encadeados (map, filter, take).
3. **Convenção simples**: Apenas `next() -> ?T` — sem interface formal complexa.
4. **Uso com while**: Integra naturalmente com `while (iter.next()) |item|`.

## Exemplo Prático

### Iterador Simples

```zig
const std = @import("std");

const Intervalo = struct {
    atual: usize,
    fim: usize,

    pub fn init(inicio: usize, fim: usize) Intervalo {
        return .{ .atual = inicio, .fim = fim };
    }

    pub fn next(self: *Intervalo) ?usize {
        if (self.atual >= self.fim) return null;
        const valor = self.atual;
        self.atual += 1;
        return valor;
    }
};

pub fn main() void {
    var iter = Intervalo.init(5, 10);
    while (iter.next()) |valor| {
        std.debug.print("{} ", .{valor}); // 5 6 7 8 9
    }
    std.debug.print("\n", .{});
}
```

### Tokenizador de Strings (da std lib)

```zig
const std = @import("std");

pub fn main() void {
    const csv = "nome,idade,cidade,país";

    // std.mem.splitScalar retorna um iterador
    var iter = std.mem.splitScalar(u8, csv, ',');

    while (iter.next()) |campo| {
        std.debug.print("Campo: '{s}'\n", .{campo});
    }
    // Campo: 'nome'
    // Campo: 'idade'
    // Campo: 'cidade'
    // Campo: 'país'
}
```

### Iterador com Estado Complexo

```zig
const std = @import("std");

fn Fibonacci() type {
    return struct {
        a: u64 = 0,
        b: u64 = 1,
        contagem: usize = 0,
        limite: usize,

        const Self = @This();

        pub fn init(limite: usize) Self {
            return .{ .limite = limite };
        }

        pub fn next(self: *Self) ?u64 {
            if (self.contagem >= self.limite) return null;
            self.contagem += 1;

            const resultado = self.a;
            const novo = self.a +| self.b; // saturating add
            self.a = self.b;
            self.b = novo;
            return resultado;
        }
    };
}

pub fn main() void {
    var fib = Fibonacci().init(10);
    while (fib.next()) |valor| {
        std.debug.print("{} ", .{valor});
    }
    // 0 1 1 2 3 5 8 13 21 34
    std.debug.print("\n", .{});
}
```

## Convenção do Iterador

```zig
// Qualquer struct com este método é um iterador:
pub fn next(self: *Self) ?ItemType {
    // Retornar próximo item ou null se acabou
}

// Uso idiomático:
while (iter.next()) |item| {
    // processar item
}
```

## Iteradores na std lib

| Iterador | Uso |
|----------|-----|
| `std.mem.splitScalar` | Dividir string por caractere |
| `std.mem.splitSequence` | Dividir por sequência |
| `std.mem.tokenizeScalar` | Tokenizar ignorando delimitadores consecutivos |
| `std.mem.window` | Janela deslizante sobre slice |
| `std.fs.Dir.iterate()` | Iterar entradas de diretório |

## Armadilhas Comuns

- **Mutabilidade**: O iterador precisa ser `var`, não `const`, pois `next()` modifica estado interno.
- **Consumo único**: A maioria dos iteradores só pode ser percorrida uma vez. Para percorrer novamente, crie outro iterador.
- **Sem reset**: Não há convenção de "reset" — crie uma nova instância.
- **null vs fim**: `null` significa "sem mais itens", não erro. Para iteradores que podem falhar, o retorno deve ser `!?T`.

## Quando Usar Iterator Pattern

Use o padrão de iterador quando:

- **Processamento sequencial**: Você precisa percorrer elementos um a um sem carregar tudo na memória.
- **Fonte de dados lazy**: Os dados são gerados sob demanda (sequências infinitas, leitura de arquivos, streams de rede).
- **Composição de transformações**: Aplicar filtros e mapeamentos em cadeia antes de consumir os resultados.
- **Abstração de origem**: A função que consome o iterador não precisa saber se os dados vêm de um array, arquivo ou rede.

## Funções Genéricas com Iteradores

Como Zig não tem interfaces formais, use `anytype` para escrever funções que aceitam qualquer iterador:

```zig
const std = @import("std");

// Aceita qualquer tipo que tenha next() -> ?T
fn contar(iter: anytype) usize {
    var count: usize = 0;
    var it = iter;
    while (it.next()) |_| count += 1;
    return count;
}

fn primeiro(iter: anytype) ?@TypeOf(iter).Next {
    var it = iter;
    return it.next();
}

// Coletar todos os itens em um ArrayList
fn coletarEmLista(
    iter: anytype,
    allocator: std.mem.Allocator,
) !std.ArrayList(@TypeOf(blk: {
    var dummy = iter;
    break :blk dummy.next().?;
})) {
    _ = allocator; // simplificado para exemplo
    @compileError("exemplo simplificado");
}
```

A convenção `next() -> ?T` funciona como um contrato implícito que o compilador verifica via duck typing.

## Boas Práticas

- **Declare como `var`**: O iterador precisa ser mutável, pois `next()` altera estado interno. `const iter = ...` causará erro de compilação ao chamar `next()`.
- **Crie novo iterador para reiterar**: Não há convenção de reset. Se precisar percorrer novamente, construa uma nova instância.
- **Use `?T` limpo para iteradores infalíveis**: Se a iteração não pode falhar, retorne `?T`. Reserve `!?T` para iteradores que lêem de fontes que podem dar erro (arquivos, rede).
- **Documente o comportamento de fim**: Deixe claro se `null` significa "sem mais dados" ou se há situações onde o iterador para prematuramente.

## Termos Relacionados

- [Optional](/glossario/optional/) — Tipo de retorno `?T` do `next()`
- [Struct](/glossario/struct/) — Iteradores são structs com estado
- [anytype](/glossario/anytype/) — Funções genéricas aceitam qualquer iterador
- [Slice](/glossario/slice/) — Fonte comum de dados para iteração

## Tutoriais Relacionados

- [Zig Design Patterns](/tutoriais/zig-design-patterns/)
- [Strings e Arrays em Zig](/tutoriais/strings-e-arrays-zig/)
- [Introdução ao Zig](/tutoriais/introducao-ao-zig/)
