2017-12-17 18 views
0

意図している用法:Lispian condマクロの実装方法は?

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

がに展開する必要があります:それはキャッチオールelse { ... }サフィックスを生成しないことを

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

注意。

私の試み:

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),+ } 
    }}; 
); 

しかし、コンパイラはelseキーワードについて文句を言います。

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

答えて

3

Rustのマクロは、Cプリプロセッサのようにテキスト置換を実行しません。さらに、マクロの結果はすでに "解析"されているので、マクロ展開の後に何かを追加するだけではマクロを展開することはできません。

コンパイラがif式の解析を既に完了しているため、最初のcond!呼び出しの後にelseを置くことはできません。 ifelseを一緒に入れる必要があります。同様に、elseの後にcond!を再度呼び出す場合は、else ifというシーケンスがネストされたif式を開始しないため、コールの前後に中カッコを追加する必要があります。

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),+ } } 
    }; 
} 

最終的には、このマクロはほとんど役に立ちません。 if式がelseでない場合、その型は常に()であると推定されます。したがって、すべてのブランチが()(または発散)と評価されない限り、展開されたマクロは型不一致エラーを生成します。

+0

ありがとうございます。 –

関連する問題