00
:
00
:
00
:
00
•Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Macro in Rust

Le macro in Rust permettono di generare codice a compile-time, riducendo la ripetizione e abilitando pattern che non sarebbero possibili con le sole funzioni.

Macro Dichiarative (macro_rules!)

macro_rules! saluta {
    () => {
        println!("Ciao, mondo!");
    };
    ($nome:expr) => {
        println!("Ciao, {}!", $nome);
    };
}

fn main() {
    saluta!();          // Ciao, mondo!
    saluta!("Mario");   // Ciao, Mario!
}

Designatori di Pattern

Designatore Corrisponde a
expr Espressione
ident Identificatore
ty Tipo
pat Pattern
stmt Statement
block Blocco di codice
literal Letterale
tt Token tree (qualsiasi cosa)

Ripetizione

macro_rules! vec_di_stringhe {
    ($($x:expr),* $(,)?) => {
        vec![$($x.to_string()),*]
    };
}

fn main() {
    let v = vec_di_stringhe!["ciao", "mondo", "rust"];
    println!("{:?}", v); // ["ciao", "mondo", "rust"]
}

Esempio: Macro HashMap

macro_rules! mappa {
    ($($chiave:expr => $valore:expr),* $(,)?) => {{
        let mut map = std::collections::HashMap::new();
        $(map.insert($chiave, $valore);)*
        map
    }};
}

fn main() {
    let capitali = mappa! {
        "Italia" => "Roma",
        "Francia" => "Parigi",
        "Spagna" => "Madrid",
    };
    println!("{:?}", capitali);
}

Macro Standard Comuni

// vec! - crea un vettore
let v = vec![1, 2, 3];

// println! / print! / eprintln! - output formattato
println!("Valore: {}", 42);

// format! - stringa formattata
let s = format!("{} + {} = {}", 1, 2, 3);

// todo! - segnaposto per codice da implementare
fn funzione_futura() -> i32 {
    todo!("Da implementare")
}

// unimplemented! - funzionalitĂ  non implementata
fn non_supportato() {
    unimplemented!()
}

// unreachable! - codice che non dovrebbe essere raggiunto
fn verifica(x: i32) {
    match x {
        1 => println!("uno"),
        2 => println!("due"),
        _ => unreachable!("Valore inaspettato"),
    }
}

// dbg! - debug rapido
let x = dbg!(5 * 2); // Stampa: [src/main.rs:1] 5 * 2 = 10

// assert! / assert_eq! / assert_ne! - asserzioni
assert!(true);
assert_eq!(2 + 2, 4);

Macro Procedurali (Panoramica)

Le macro procedurali operano sull’AST e sono più potenti:

Derive Macro

use serde::{Serialize, Deserialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Utente {
    nome: String,
    eta: u32,
}

Attribute Macro

#[tokio::main]
async fn main() {
    // Il codice asincrono va qui
}

#[test]
fn mio_test() {
    assert!(true);
}

Function-like Macro

// sqlx usa macro function-like
let utenti = sqlx::query!("SELECT * FROM utenti WHERE id = $1", id)
    .fetch_all(&pool)
    .await?;

Conclusione

Le macro sono uno strumento potente di Rust per la metaprogrammazione. Le macro dichiarative (macro_rules!) coprono la maggior parte dei casi d’uso, mentre le macro procedurali offrono potenza illimitata per generazione di codice. Usa le macro quando le funzioni non bastano, ma preferisci le funzioni quando possibile per una migliore leggibilità e diagnostica degli errori.