【问题标题】:Rust macros: match argument as closure but differentiate between non-closure-expression and closure-expressionsRust 宏:将参数匹配为闭包,但区分非闭包表达式和闭包表达式
【发布时间】:2021-05-16 17:38:59
【问题描述】:

我想创建一个可以这样使用的宏

    generate_code!(println!("macro argument is expression"));
    generate_code!(|| println!("macro argument is closure"));

不幸的是,两个宏参数都匹配为“expr”。我的宏应该足够聪明,可以在第一种情况下添加||。这在 Rust 中可行吗?

macro_rules! generate_code {
    // for `generate_code!(println!())`
    ($expression:expr) => {do_sth(|| $expression)};

    // for `generate_code!(|| println!())`
    ($closure:expr???) => {do_sth($closure)};
}

【问题讨论】:

    标签: rust macros


    【解决方案1】:

    您可以显式匹配闭包标记:

    macro_rules! generate_code {
        (|| $expression:expr) => {do_sth(|| $expression)};
        (move || $expression:expr) => {do_sth(move || $expression)};
        ($expression:expr) => {do_sth(|| $expression)};
    }
    

    (我也包含了经常使用的 move 闭包。)

    例如,它按预期运行:

    fn do_sth(f: impl FnOnce()) {
        f();
    }
    
    fn main() {
        generate_code!(println!("macro argument is expression"));
        generate_code!(|| println!("macro argument is closure"));
        generate_code!(move || println!("macro argument is move closure"));
    }
    

    请注意,这种方法可能会导致令人惊讶的结果,因为它真的不会检测到闭包,它只会检测文字 || 标记序列。如果你将闭包伪装成generate_code!((|| println!("xxx"))),或者如果闭包接受参数,如generate_code!(|foo| println!("{}", foo)),则表达式将被视为非闭包表达式,并将被填充到闭包中。根据do_sth 接受的类型界限,结果要么是一个神秘的编译错误,例如“期望单元类型,发现闭包”,要么是(更糟糕的)成功编译和不需要的行为。

    【讨论】:

      猜你喜欢
      • 2017-03-31
      • 2014-10-15
      • 1970-01-01
      • 2013-12-14
      • 2020-12-30
      • 1970-01-01
      • 1970-01-01
      • 2013-09-21
      • 2013-04-16
      相关资源
      最近更新 更多