如何使用重复创建带有可选参数的Rust宏? [英] How do I create a Rust macro with optional parameters using repetitions?

查看:63
本文介绍了如何使用重复创建带有可选参数的Rust宏?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm currently looking into Rust macros and I can not find any detailed documentation on repetitions. I would like to create macros with optional parameters. This would be my idea:

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

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

This example seems to be outdated, since I can not compile it. The Rust book mentions this topic just very briefly. How do I get this example to work?

推荐答案

Rust图书的第一版具有

The first edition of the Rust book has a rather long chapter on macros, but the section on repetitions is a bit shy on examples...

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

There are several ways to handle optional arguments in macros. If you have an optional argument that can only occur once, then you shouldn't use repetitions: you should instead define multiple patterns in your macro, like this:

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,); 的形式调用该宏.有关相关情况,请参见如何在宏中允许可选的尾随逗号?.

If you want to allow an arbitrary number of arguments, then you need repetition. Your original macro doesn't work because you put the comma outside the repetition, so you'd have to invoke the macro as single_opt!(4,4,);. See How to allow optional trailing commas in macros? for a related case.

如果参数个数固定且后面有重复,则可以将逗号放在重复中作为第一个标记:

If you have a fixed number of arguments followed by a repetition, you can put the comma inside the repetition as the first token:

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

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

However, it doesn't work in this specific case:

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)

所以我们必须回到定义两种模式:

So we'll have to go back to defining two patterns:

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 是代码" *""(表示零个或多个")或 + 表示一个或多个事件".

A repetition takes the form $( PATTERN ) SEPARATOR COUNT, where PATTERN is the pattern you want to repeat, SEPARATOR is an optional token that separates each repetition (here, it's ,) and COUNT is either * for "zero or more occurrences" or + for "one or more occurrences".

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

Then, in the macro expansion, we need a repetition block to be able to access $opt. The syntax is exactly the same, but note that the separator doesn't have to be the same (here, there's no separator in the expansion).

这篇关于如何使用重复创建带有可选参数的Rust宏?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆