Noções Básicas de Macros
10 exemplos para você começar com Macros - 7 básicos e 3 intermediários.
Pré-requisitos
- Rust 1.97.0 (edição 2024)
- Compreensão de que macros se expandem em tempo de compilação
Exemplos Básicos
1. Declarativas vs. Procedurais
// declarativa: macro_rules!
macro_rules! say_hello {
() => { println!("Hello"); };
}
// procedural: #[derive(Serialize)] implementada por crate de macro proc- Macros declarativas correspondem a padrões de tokens
- Macros procedurais são funções Rust em fluxos de tokens
- Ambas executam em tempo de compilação
- Prefira funções/genéricos quando possível
Relacionado: macro_rules!
2. macro_rules! Hello
macro_rules! greet {
($name:expr) => {
println!("Hello, {}", $name);
};
}
fn main() {
greet!("Rust");
}$name:exprcaptura uma expressão- Expande para Rust puro no local da chamada
- Sem verificação de tipo dentro do matcher até a expansão
- Use
cargo expandpara depurar a saída
3. Higiene de Macros
Macros não capturam acidentalmente variáveis locais do chamador (higiênicas para macro_rules!).
macro_rules! double {
($x:expr) => { $x * 2 };
}
fn demo() {
let x = 10;
assert_eq!(double!(5), 10); // usa 5, não o x local
}- A higiene reduz colisões de nomes surpreendentes
- Macros proc podem quebrar a higiene se gerarem identificadores descuidadamente
- Ainda pense nos caminhos de crate exportados
Relacionado: Depurando Macros
4. Macros Embutidas
println!("debug = {:?}", dbg!(value));
todo!();
unreachable!();format!,vec!,panic!são macrosinclude_str!,env!incorporam em tempo de compilaçãocfg!econcat!para compilação condicional
5. Quando Não Usar Macros
// Prefira função genérica:
fn max<T: Ord>(a: T, b: T) -> T {
if a > b { a } else { b }
}- Funções têm melhores erros e suporte de IDE
- Macros para DSLs de sintaxe repetitiva
- Macros proc
derivepara traits
Relacionado: Melhores Práticas de Macros
6. Especificadores de Fragmento
macro_rules! id {
($x:ident) => { stringify!($x) };
}Especificadores comuns: expr, ident, ty, path, stmt, block, tt.
7. Repetição
macro_rules! vec_str {
($($x:expr),*) => {
vec![$($x.to_string()),*]
};
}$()*repete o padrão$(,)*separação opcional por vírgula- Potencializa
vec!e APIs similares
Relacionado: macro_rules!
Exemplos Intermediários
8. Macros Derive
#[derive(Debug, Clone, serde::Serialize)]
struct User { id: u64 }- Implementadas como macros proc em crates externos
syn+quoteanalisam e geram código
Relacionado: Macros Derive
9. Macros de Atributo
#[tokio::main]
async fn main() { }- Macros proc de atributo reescrevem o item abaixo
- Usadas por frameworks para redução de boilerplate
Relacionado: Macros de Atributo
10. Depurando Expansão
cargo install cargo-expand
cargo expand -p mycrate my_fn- Sempre expanda quando erros de macro confundirem
- Combine com
trace_macros!(instável) com moderação
Relacionado: Depurando Macros
Versões da Pilha: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4 e Polars 0.46+.