在Rust宏中调用不同数量参数的函数

4
我需要一个宏,它可以调用具有不同参数数量的函数,或者生成有效的参数列表的宏(重复参数)。我可以明确地向宏提供关于参数数量的信息,但是我无法生成函数的参数列表 - 我总是会在宏返回表达式而不是令牌树上遇到问题。我制作了以下playground示例: playground example
macro_rules! call (
    ($f: expr, $($params:tt)*) => {
        $f(make_params!($($params:tt)*))
    };
);

macro_rules! make_params {
    () => {};
    (I $($params: tt)*) => {
        1, make_params!($($params:tt)*)
    };
}


fn foo(a: i32, b: i32, c: i32) {
    println!("foo: {} {} {}", a, b, c);
}

fn bar(a: i32, b: i32) {
    println!("bar: {} {}", a, b);
}

fn main() {
    call!(foo, I I I);
    call!(bar, I I);
}

编译器报错如下:
error: macro expansion ignores token `,` and any following
  --> src/main.rs:10:10
   |
10 |         1, make_params!($($params:tt)*)
   |          ^
   |
note: caused by the macro expansion here; the usage of `make_params!` is likely invalid in expression context
  --> src/main.rs:3:12
   |
3  |         $f(make_params!($($params:tt)*))
   |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
...

如何将make_params!的返回值视为令牌流(或类似)而不是表达式?

我的实际用例比这个玩具示例更复杂。我的函数有多个参数类型,这些类型以不同的方式构造。在我的情况下,仅制作宏call1call2!等并不是一个好的解决方案,因为我需要像call_IIOOIcall_IIIO等这样的东西。


3
宏必须展开为有效的AST元素。1, foo不是一个有效的AST元素。 翻译注解:
  • AST(抽象语法树)是计算机科学中用于表示程序代码结构的一种树形数据结构。
  • "expanding to" 意为 "展开为", "valid"意为 "有效的", "element"意为 "元素"。
  • 句子结构简单明了,没有需要解释的术语或难以理解的部分。
- mcarton
@mcarton 谢谢!嗯...既然没有直接构造参数列表的方法,你能想到其他的解决方案吗? - Tomáš Gavenčiak
1个回答

4

您需要逐步构建函数调用,并在最后一次性地发出它:

macro_rules! call (
    ($f: expr, $($params:tt)*) => {
        make_call!($f, () $($params)*)
    };
);

macro_rules! make_call {
    ($f: expr, ($($args:tt)*)) => { $f($($args)*) };
    ($f: expr, () I $($params:tt)*) => {
        make_call!($f, (1) $($params)*)
    };
    ($f: expr, ($($args:tt)*) I $($params:tt)*) => {
        make_call!($f, ($($args)*, 1) $($params)*)
    };
}

playground


我看到这里使用累加器来构建参数列表。我曾经想过类似的方法,但不知道如何实现。这正是我所需要的 - 谢谢! - Tomáš Gavenčiak

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接