【问题标题】:How to use variadic macros to call nested constructors?如何使用可变参数宏调用嵌套构造函数?
【发布时间】:2014-07-01 14:08:11
【问题描述】:

我正在尝试在 Rust 中创建一个可以让我编写的宏

make_list!(1, 2, 3)

而不是

Node::new(1, Node::new(2, Node::new(3, None)))

它应该适用于任意数量的“参数”,包括零。这是我目前所拥有的:

macro_rules! make_list(
    () => (
        None
    );
        ( $x:expr, $( $more:expr ),* ) => (
        Node::new($x, make_list!( $( $more ),* ))
    )
);

但我收到以下错误:

error: unexpected end of macro invocation
  --> src/main.rs:19:42
   |
19 |             Node::new($x, make_list!( $( $more ),* ))
   |                                          ^^^^^

我无法理解这一点。据我所知,它应该可以工作。我做错了什么?

完整代码:

type List<T> = Option<Box<Node<T>>>;

struct Node<T> {
    value: T,
    tail: List<T>,
}

impl<T> Node<T> {
    fn new(val: T, tai: List<T>) -> List<T> {
        Some(Box::new(Node::<T> {
            value: val,
            tail: tai,
        }))
    }
}

macro_rules! make_list(
    () => (
        None
    );
    ( $x:expr, $( $more:expr ),* ) => (
        Node::new($x, make_list!( $( $more ),* ))
    )
);

fn main() {
    let _list: List<i32> = make_list!(1, 2, 3, 4, 5, 6, 7, 8, 9);
}

【问题讨论】:

  • 您的宏需要 0 或 2 个参数,但您只传递了 1 个
  • @Arjan:但我认为这就是 $(...),* 的用途。它应该匹配零到更多的参数。不应该吗?

标签: macros rust


【解决方案1】:

扩展错误:你会遇到只有一个值的情况,所以它写成make_list!(1)。但是,没有任何规则可以匹配,对于第二条规则,在使用表达式 x 之后,需要一个逗号,但没有提供。

所以你需要让它适用于make_list!(1) 而不仅仅是(事实上,只是不是make_list!(1,)。为此,请在重复部分中添加逗号,如下所示:

macro_rules! make_list(
    () => (
        None
    );
    ( $x:expr $( , $more:expr )* ) => (
        Node::new($x, make_list!( $( $more ),* ))
    )
);

奖励:如果你愿意,你可以写 make_list![1, 2, 3] 而不是 make_list!(1, 2, 3)

【讨论】:

  • 谢谢!我想我只是太习惯于 C++ 可变参数模板的魔力了。 :)
  • 这种方法不再有效;见here
  • 好像works again.
【解决方案2】:

正如@chris-morgan 的回答所指出的,没有考虑扩展单论点的情况。

因此您可以在扩展中包含逗号,或者在宏中添加单个大小写:

两者的示例,单个参数:

macro_rules! make_list {
    () => (
        None
    );
    ($x:expr) => (
        Node::new($x, None)
    );
    ($x:expr, $($more:expr),+) => (
        Node::new($x, make_list!($($more),*))
    );
}

在扩展中包含逗号:

macro_rules! make_list {
    () => (
        None
    );
    ($x:expr $(, $more:expr)*) => (
        Node::new($x, make_list!($($more),*))
    );
}

这是一个基于问题并针对 Rust 1.14 更新的完整示例:

type List<T> = Option<Box<Node<T>>>;

#[derive(Debug)]
struct Node<T> {
    value: T,
    tail: List<T>
}

impl<T> Node<T> {
    fn new(val: T, tai: List<T>) -> List<T> {
        Some(Box::new(Node::<T> { value: val, tail: tai }))
    }
}

macro_rules! make_list {
    () => (
        None
    );
    ($x:expr $(, $more:expr)*) => (
        Node::new($x, make_list!($($more),*))
    );
}

fn main() {
    let list: List<i64> = make_list!();
    println!("{:?}", list);
    let list: List<i64> = make_list!(1);
    println!("{:?}", list);
    let list: List<i64> = make_list!(1,2,3,4,5,6,7,8,9);
    println!("{:?}", list);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-06-17
    • 1970-01-01
    • 1970-01-01
    • 2017-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多