如何使用重复创建带有可选参数的Rust宏?

时间:2015-12-19 16:58:40

标签: macros pattern-matching rust

我目前正在研究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书中非常简短地提到了这个主题。我如何让这个例子起作用?

1 个答案:

答案 0 :(得分:13)

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

如果您有一个固定数量的参数后跟一个重复,您可以将逗号放在重复内作为第一个标记:

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

但是,它并不适用于这种特殊情况:

<anon>:2:33: 2:47 error: `$mand_2:expr` is followed by a sequence repetition, which is not allowed for `expr` fragments
<anon>:2     ($mand_1:expr, $mand_2:expr $(, $opt:expr)*) => {
                                         ^~~~~~~~~~~~~~

因此,我们必须回过头来定义两种模式:

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是一个可选的标记,用于分隔每个重复(此处,它是&#39; s { {1}})和, COUNT为&#34;零次或多次出现&#34;或*代表&#34;一次或多次事件&#34;。

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