我目前正在研究Rust宏,但找不到有关重复的任何详细文档。我想创建带有可选参数的宏。这是我的主意:

macro_rules! single_opt {
    ($mand_1, $mand_2, $($opt:expr)* ) =>{
        match $opt {
            Some(x) => println!("1. {} 2. {}, 3. {}", $mand_1, $mand_2, x);
            None => single_opt!($mand_1, $mand_2, "Default");
        }
    }
}

fn main() {
    single_opt!(4,4);
}

这个example似乎已过时,因为我无法编译它。 Rust的书非常简短地提到了这个主题。我如何才能使该示例正常工作?

最佳答案

Rust书籍的第一版有一个rather long chapter on macros,但是关于重复的部分对示例有些害羞...

有几种方法可以处理宏中的可选参数。如果您有一个只能出现一次的可选参数,则不应使用重复:您应该在宏中定义多个模式,如下所示:

macro_rules! single_opt {
    ($mand_1:expr, $mand_2:expr) => {
        single_opt!($mand_1, $mand_2, "Default")
    };
    ($mand_1:expr, $mand_2:expr, $opt:expr) => {
        println!("1. {} 2. {}, 3. {}", $mand_1, $mand_2, $opt)
    };
}

fn main() {
    single_opt!(4, 4);
}

如果要允许任意数量的参数,则需要重复。您的原始宏无效,因为您将逗号放在了重复之外,因此您必须将宏作为single_opt!(4,4,);调用。有关相关情况,请参见How to allow optional trailing commas in macros?

如果您有固定数量的参数,后跟一个重复,则可以将逗号放在重复中作为第一个标记:
macro_rules! single_opt {
    ($mand_1:expr, $mand_2:expr $(, $opt:expr)*) => {
        println!("1. {} 2. {}, 3. {}", $mand_1, $mand_2, $($opt),*)
    };
}

但是,在这种特定情况下不起作用:

error: 3 positional arguments in format string, but there are 2 arguments
 --> src/main.rs:3:22
  |
3 |         println!("1. {} 2. {}, 3. {}", $mand_1, $mand_2, $($opt),*)
  |                      ^^    ^^     ^^
...
8 |     single_opt!(4, 4);
  |     ------------------
  |     |
  |     in this macro invocation
  |     in this macro invocation
  |     in this macro invocation
  |
  = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

因此,我们必须回到定义两种模式:
macro_rules! single_opt {
    ($mand_1:expr, $mand_2:expr) => {
        single_opt!($mand_1, $mand_2, "Default")
    };
    ($mand_1:expr, $mand_2:expr, $($opt:expr),*) => {
        {
            println!("1. {} 2. {}", $mand_1, $mand_2);
            $(
                println!("opt. {}", $opt);
            )*
        }
    };
}

fn main() {
    single_opt!(4, 4, 1, 2);
}

重复的形式为$( PATTERN ) SEPARATOR COUNT,其中PATTERN是您想要重复的模式,SEPARATOR是分隔每个重复的可选标记(此处为,),而COUNT*(表示“零次或多次”)或+(表示“一次或多次”)更多的事件”。

然后,在宏扩展中,我们需要一个重复块才能访问$opt。语法完全相同,但是请注意,分隔符不必相同(此处,扩展中没有分隔符)。

关于macros - 如何使用重复创建带有可选参数的Rust宏?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34373169/

10-11 04:01
查看更多