Aula 19 - Macros Declarativas e Procedurais em Rust 🪄
Objetivo Pedagógico
Objetivo: Metaprogramação em Rust: Macros declarativas com macro_rules!, macros procedurais (Derive Macros, Attribute Macros e Function-like Macros) e manipulação da Árvore de Sintaxe Abstrata (AST) com syn/quote.
📑 1. Fundamentos Teóricos & Análise Técnica
Diferente das macros em C (que operam como uma substituição cega de texto bruto no pré-processador antes da compilação, abrindo brechas para bugs graves), as Macros em Rust operam diretamente sobre a Árvore de Sintaxe Abstrata (AST - Abstract Syntax Tree) da linguagem, preservando a segurança de tipos e o escopo léxico (Hygiene).
Categorias de macros em Rust: 1. Macros Declarativas (macro_rules!): Baseadas em casamento de padrões (Pattern Matching). Recebem fragmentos sintáticos tipados ($x:expr, $t:ty, $i:ident) e expandem blocos de código repetitivos. 2. Macros Procedurais (Proc Macros): Funções Rust compiladas como plugins de compilador que recebem um stream de tokens (TokenStream), processam sua estrutura via bibliotecas como syn e emitem um novo TokenStream transformado com quote: - Custom Derive: Anotações como #[derive(Serialize, Deserialize)] que implementam traits automaticamente. - Attribute Macros: Decoradores customizados como #[get("/users")]. - Function-like Macros: Chamadas personalizadas como sqlx::query!("SELECT...") com validação de banco em tempo de compilação.
📐 Arquitetura Conceitual & Diagrama de Fluxo
flowchart LR
Source["Código Fonte: #[derive(Audit)] struct Order"] --> Parser["Parser de Tokens (syn::parse)"]
Parser --> AST["Árvore de Sintaxe Abstrata (AST)"]
AST --> ProcMacro["Macro Procedural (Geração de Código com quote!)"]
ProcMacro --> GeneratedCode["Código Rust Expandido: impl Audit for Order { ... }"]
GeneratedCode --> Compiler["Compilador rustc (Compilação Final com Tipagem Estrita)"]
style Source fill:#e1f5fe,stroke:#01579b
style ProcMacro fill:#fff3e0,stroke:#e65100
style GeneratedCode fill:#e8f5e9,stroke:#2e7d32 🔍 Pilares e Diretrizes Técnicas
Nesta unidade, aprofundamos os seguintes conceitos fundamentais: - Higiene Léxica (Macro Hygiene): Variáveis criadas dentro de macros não vazam nem colidem com variáveis do escopo de chamada. - Validação Estática Avançada: Possibilidade de validar formatos de dados (ex: queries SQL, JSONs, regexes) durante o cargo build. - Eliminação de Código Boilerplate: Implementação automática de padrões repetitivos sem custo de execução. - Inspeção com cargo expand: Ferramenta essencial para inspecionar visualmente o código final gerado após a expansão das macros.
🛠️ 2. Implementação Prática em Rust Metaprogramação e Macros
Abaixo está a implementação técnica de referência, estruturada com padrões de engenharia de software e foco em robustez:
// declarative_macros.rs (Macro Declarativa com Casamento de Padrões)
// Macro declarativa para inicializar mapas com sintaxe limpa
macro_rules! hashmap {
( $( $key:expr => $val:expr ),* $(,)? ) => {
{
let mut map = ::std::collections::HashMap::new();
$(
map.insert($key, $val);
)*
map
}
};
}
fn main() {
// Uso da macro com sintaxe concisa
let scores = hashmap! {
"Azul" => 10,
"Vermelho" => 25,
"Verde" => 50,
};
println!("Pontuação Azul: {:?}", scores.get("Azul"));
}
💡 Análise Passo a Passo do Código
- Captura de Expressões:
$key:expr => $val:exprcaptura pares de expressões separados pelo operador=>. - Repetição com $(...)*: O combinador expande dinamicamente uma chamada
map.insert(...)para cada par fornecido. - Vírgula Opcional Trailing:
$(,)?aceita elegantemente vírgulas no último item sem quebrar a compilação.
🎯 3. Próximos Passos & Sequência Didática
-
Slides da Aula
-
Quiz de Fixação
-
Exercícios Práticos
-
Desafio de Projeto