No description
Find a file
2026-08-31 11:22:39 +02:00
.woodpecker chore: migrate CI to .woodpecker/{push,branch}.yml 2026-08-31 11:22:39 +02:00
src fix(033): pedagogical MINOR fixes 2026-08-31 11:22:39 +02:00
tests initial content 2026-08-31 11:22:34 +02:00
.gitignore Initial commit 2026-08-31 09:21:58 +00:00
Cargo.lock initial content 2026-08-31 11:22:34 +02:00
Cargo.toml chore: declare MSRV 1.85 (edition 2024) 2026-08-31 11:22:39 +02:00
LICENSE chore: add AGPL-3.0 license and standard .gitignore 2026-08-31 11:22:39 +02:00
README.md fix(033): pedagogical MINOR fixes 2026-08-31 11:22:39 +02:00

Lição 33: Funções Anônimas (Closures)

1. Narrativa

O piloto do mecha Æther cria protocolos rápidos em tempo real — closures são funções anônimas que capturam o ambiente ao redor. Diferente de funções nomeadas, closures podem acessar variáveis do escopo onde são criadas, tornando-as perfeitas para protocolos de resposta imediata no cockpit.

2. Conceito

Closures são funções anônimas que capturam seu ambiente:

  • Sintaxe: |parametros| corpo — ex: |x| x * 2
  • Fn: Captura por referência imutável — pode ser chamada múltiplas vezes
  • FnMut: Captura por referência mutável — pode modificar estado interno
  • FnOnce: Captura por posse (ownership) — só pode ser chamada uma vez
  • move: Força captura por ownership — necessário ao retornar closures
  • Retorno: impl Fn(T) -> U — retornar closures de funções

3. Requisitos

  • Criar closures básicas sem captura
  • Capturar variáveis do ambiente com move
  • Usar RefCell para estado mutável em closures FnMut
  • Passar closures como parâmetros e retorná-las de funções

🔭 Referência futura: Esta lição usa std::cell::RefCell para obter mutabilidade interior dentro de uma closure FnMut. RefCell é uma "smart pointer" com check de borrow em runtime — o detalhamento completo vem na Lição 037 (Tipos Box) e em Lição 043 (Estado Compartilhado). Aqui basta saber: RefCell<T>::borrow_mut() devolve uma referência mutável verificada em runtime (pânico se houver conflito de borrow) e borrow() devolve uma imutável. A regra do RefCell é a mesma do borrow checker, só que aplicada em tempo de execução.

Também usamos métodos de iterators (como dados.sum() em consumir_recurso) para agregar os dados capturados pela closure. O detalhamento completo de iterators e seus adaptadores vem na Lição 034 (Iterators) — aqui basta saber que .sum() consome o iterator e soma todos os elementos.

4. Design de Dados

graph LR
    A["Fn: |x| x * 2"] --> B["Sem captura"]
    C["Fn: move |x| x + base"] --> D["Captura por valor imutável"]
    E["FnMut: RefCell + move"] --> F["Estado mutável interno"]
    G["FnOnce: move || dados.sum()"] --> H["Consome dados"]
    I["Parâmetro: impl Fn(i32) -> i32"] --> J["Closure como argumento"]

5. Diagrama de Fluxo

flowchart TD
    A[Início] --> B{Tipo de closure?}
    B -->|Leitura| C["Fn — captura &T"]
    B -->|Modificação| D["FnMut — captura &mut T"]
    B -->|Consumo| E["FnOnce — captura T"]
    C --> F["Pode chamar múltiplas vezes"]
    D --> G["Precisa ser mut para chamar"]
    E --> H["Só pode chamar uma vez"]
    F --> I[Retornar closure com impl Fn]
    G --> I
    H --> I

6. Funções

Função Descrição
criar_dobrador Closure Fn sem captura: `
calibrar_com_base Closure Fn com captura move: soma base
gerar_acumulador Closure FnMut com RefCell: acumula estado
consumir_recurso Closure FnOnce: consome Vec e soma
aplicar_protocolo Recebe closure como parâmetro
criar_filtro Retorna closure que filtra por limiar

7. Exemplo

let dobrador = criar_dobrador();
assert_eq!(dobrador(5), 10);
let calibrar = calibrar_com_base(100);
assert_eq!(calibrar(50), 150);
let mut acum = gerar_acumulador(0);
assert_eq!(acum(10), 10);
assert_eq!(acum(5), 15);
let filtro = criar_filtro(50);
assert!(filtro(60));
assert!(!filtro(30));

8. Missão

  1. Implementar criar_dobrador — closure pura sem captura, trait Fn
  2. Implementar calibrar_com_base — captura com move, trait Fn
  3. Implementar gerar_acumuladorRefCell para mutabilidade interna, trait FnMut
  4. Implementar consumir_recurso — consome dados, trait FnOnce
  5. Implementar aplicar_protocolo — closure como parâmetro com impl Fn
  6. Implementar criar_filtro — closure como retorno com captura e move

9. Como Executar

cargo build
cargo test
cargo clippy -- -D warnings
cargo fmt --check

10. Dicas

  • Toda FnOnce é também FnMut e Fn — o inverso não é verdade
  • move é necessário ao retornar closures de funções — sem ele, as variáveis capturadas seriam dropping
  • RefCell<T> permite mutabilidade interior em contexto Fn — segurança em runtime (ver Lições 037 e 043 para o detalhamento completo)
  • impl Fn(T) -> U no retorno permite devolver closures sem nomear o tipo exato