将嵌套结构字段路径作为宏参数传递

我是 Rust 的新手,我在编译以下代码时遇到了问题:

#![feature(trace_macros)]

fn main() {
    #[derive(Debug)]
    struct Inner {
      value: u8
    }
    
    #[derive(Debug)]
    struct Outer {
      inner: Inner
    }
    
    let mut x  = Outer { inner: Inner { value: 64 } };
    
    /********/
    
    macro_rules! my_macro {
        ($field_path:expr, $v:expr) => {
            x.$field_path = $v;
        }
    }

    trace_macros!(true);    
    // my_macro!(inner, Inner { value: 42 }); // only works with $field_path:ident
    my_macro!(inner.value, 42); // expected output: x.inner.value = 42;
    trace_macros!(false);
    
    x . inner.value = 42; // works fine
    
    assert_eq!(42, x.inner.value);
}

我收到以下错误:

error: unexpected token: `inner.value`
  --> src/main.rs:20:15
   |
20 |             x.$field_path = $v;
   |               ^^^^^^^^^^^
...
26 |     my_macro!(inner.value, 42); // expected output: x.inner.value = 42;
   |     --------------------------- in this macro invocation
   |

...

error: expected one of `.`, `;`, `?`, `}`, or an operator, found `inner.value`
  --> src/main.rs:20:15
   |
20 |             x.$field_path = $v;
   |               ^^^^^^^^^^^ expected one of `.`, `;`, `?`, `}`, or an operator
...
26 |     my_macro!(inner.value, 42); // expected output: x.inner.value = 42;
   |     --------------------------- in this macro invocation
   |

...

但是,trace_macro似乎能够扩展my_macro!

note: trace_macro
  --> src/main.rs:26:5
   |
26 |     my_macro!(inner.value, 42); // expected output: x.inner.value = 42;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: expanding `my_macro! { inner . value, 42 }`
   = note: to `x . inner.value = 42 ;` <<< exactly what I am looking for

如果我将$field_path参数保持为ident,我只是得到no rules expected the token `.` ,我想这是有道理的,因为.是一个运算符。我错过了什么?

游乐场链接

回答

我认为问题在于inner.value包含点运算符的事实。

那正是你的问题。没有允许您匹配和/或字段访问表达式的单个片段说明符。使用( expressions )的问题在于,当展开它时,它本质上是用括号括起来的,即,这没有意义,因此为什么会得到.identexprx.(inner.value)"unexpected token `inner.value`"

但是,您确实可以使用ident,您只需要使用重复即可。

简而言之,而不是$field_path:ident然后你做$( $field_path:ident ).+。然后扩展它,而不是x.$field_path然后你做x. $( $field_path ).+

macro_rules! my_macro {
    ($($field_path:ident).+, $v:expr) => {
        x.$($field_path).+ = $v;
    };
}

// Now both are allowed
my_macro!(inner.value, 42);
my_macro!(inner, Inner { value: 64 });


以上是将嵌套结构字段路径作为宏参数传递的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>