2017-12-17 5 views
0

Beabsichtigte Nutzung:Wie implementiert man das Lispian Cond Makro?

if x > 5 { 0 } else if x < 3 { 1 } else if true { -1 } 

Beachten Sie, dass es kein allumfassendes else { ... } Suffix produzieren:

cond! { 
    x > 5 => 0, 
    x < 3 => 1, 
    true => -1 
} 

erweitern sollte.

Mein Versuch:

macro_rules! cond(
    ($pred:expr => $body:expr) => {{ 
     if $pred {$body} 
    }}; 
    ($pred:expr => $body:expr, $($preds:expr => $bodies:expr),+) => {{ 
     cond! { $pred => $body } else cond! { $($preds => $bodies),+ } 
    }}; 
); 

Allerdings wirft der Compiler über die else Schlüsselwort.

error: expected expression, found keyword `else` 
    --> src/main.rs:32:34 
    | 
32 |   cond! { $pred => $body } else cond! { $($preds => $bodies),+ } 
    |         ^^^^ 

Antwort

3

Makros in Rust führen keine Textersetzung wie der C-Präprozessor durch. Darüber hinaus ist das Ergebnis eines Makros bereits "geparst", so dass Sie nicht einfach etwas nach dem Makroaufruf anhängen können, der Teil des Makros sein soll.

In Ihrem Fall können Sie keine else nach dem ersten Aufruf cond! aufrufen, da der Compiler bereits den Ausdruck if geparst hat; Sie müssen die if und die else zusammen setzen. Wenn Sie cond! erneut nach dem else aufrufen, müssen Sie ebenfalls Klammern um den Aufruf hinzufügen, da die Sequenz else if einen verschachtelten Ausdruck if nicht beginnt.

macro_rules! cond { 
    ($pred:expr => $body:expr) => { 
     if $pred { $body } 
    }; 
    ($pred:expr => $body:expr, $($preds:expr => $bodies:expr),+) => { 
     if $pred { $body } else { cond! { $($preds => $bodies),+ } } 
    }; 
} 

Letztendlich ist dieses Makro jedoch ziemlich nutzlos. Ein if Ausdruck ohne eine else Klausel wird immer als () bezeichnet. Wenn also nicht alle Zweige auf () (oder divergent) ausgewertet werden, erzeugt das erweiterte Makro Typenkonfliktfehler.

+0

Vielen Dank für die Erklärung. –

Verwandte Themen