2015-06-03 9 views
5

Come di Rust 1.0, non c'è modo per raggruppare più modelli in un unico legame:Le macro possono espandersi in una combinazione di motivi?

// It does not compile 
match x as char { 
    b @ ('A' | 'Z') => println!("A or Z: {}", b), 
    _ => println!("Try again") 
} 

// Correct version 
match x as char { 
    b @ 'A' | b @ 'Z' => println!("A or Z: {}", b), 
    _ => println!("Try again") 
} 

mi chiedevo se una macro potrebbe fare il lavoro sporco di legare tutte le diverse possibilità. Qui è un tentativo di parziale:

macro_rules! bind_alternatives { 
    ($x:ident, $e:expr) => ($x @ $e); 
    ($x:ident, $e1:expr, $e2:expr) => (
     $x @ $e1 | $x @ $e2 
    ); 
} 

fn main() { 
    let x = 'a'; 

    match x { 
     bind_alternatives!(z, 'a', 'c') => println!("Matched"), 
     _ => println!("No luck") 
    }; 
} 

Questo non può essere compilato:

example.rs:4:18: 4:19 error: macro expansion ignores token `|` and any following 
example.rs:4   $x @ $e1 | $x @ $e2 
            ^
example.rs:12:9: 12:40 note: caused by the macro expansion here; the usage of `bind_alternatives` is likely invalid in this context 
example.rs:12   bind_alternatives!(z, 'a', 'c') => println!("Matched"), 

Capisco che le macro possono essere espansi in schemi, e la prima coppia di bind_alternatives funziona. È possibile generalizzare a più di 1 possibilità? In caso contrario, cosa lo impedisce?

+1

Non ho una risposta completa, ma ''a' | 'c'' non è un pattern, è una sintassi specifica per combinazione per la combinazione di pattern. – bluss

risposta

4

Una macro è in grado di espandersi a cose come modelli, espressioni ed elementi, ma non tutto; in particolare, le macro si espandono per completare i nodi AST, ma ciò di cui si sta parlando qui non è un nodo AST completo.

Ogni ramo di un'espressione match può avere uno o più motivi separati da tubi e un reticolo opzionale (if condition). Questa è tutta una speciale sintassi match, e quindi non un nodo AST completo, e quindi non qualcosa a cui una macro può espandersi.

Il parser sta cercando un pattern in quel punto del suo parsing, quindi espande la macro come un pattern, che si conclude prima dello |, che non rientra in una grammatica del modello. La macro ha quindi prodotto più di quello che può essere consumato e il resto viene scartato con un errore.