我的或模式程序宏有什么问题导致“宏扩展忽略标记`|`”?

问题描述

考虑以下示例代码

#[derive(Clone,copy)]
#[allow(dead_code)]
enum Enum {
    A { a: u8,b: u8 },B { a: u8 },C { b: u8 },}

fn foo(e: Enum) -> Option<u8> {
    match e {
        Enum::A { a,.. } | Enum::B { a,.. } => Some(a),// wanted: common!(Enum::A,Enum::B { a }) => Some(a),_ => None,}
}

fn main() {
    let a = Enum::A { a: 1,b: 2 };
    let b = Enum::B { a: 1 };
    let c = Enum::C { b: 2 };
    assert_eq!(foo(a),Some(1));
    assert_eq!(foo(b),Some(1));
    assert_eq!(foo(c),None);
}

playground link

如您所见,我想为此编写一个速记宏 (common!)。如果 enum 字段声明变得更长(例如,更多的具有更长名称的字段),这将减少冗长。

(我想使用 | 作为分隔符,但我没有设法解析它。)

这是我对实现的尝试:

use proc_macro::TokenStream;
use quote::quote;
use syn::{
    parse::{Parse,ParseBuffer,Result},punctuated::Punctuated,spanned::Spanned,Error,Member,Pat,PatPath,PatStruct,Path,Token,};

#[proc_macro]
pub fn common(input: TokenStream) -> TokenStream {
    let Syntax: Result<CommonSyntax> = syn::parse(input);
    match Syntax {
        Ok(CommonSyntax { types,fields }) => {
            let fields_pattern = quote! {
                {
                    #(
                        #fields,)*
                    ..
                }
            };
            let output = quote! {
                #(
                    #types #fields_pattern
                )|*
            };
            output.into()
        }
        Err(e) => e.to_compile_error().into(),}
}

struct CommonSyntax {
    types: Vec<Path>,fields: Vec<Member>,}


impl Parse for CommonSyntax {
    fn parse(input: &ParseBuffer) -> Result<Self> {
        let mut types = Vec::new();
        let mut fields = None;
        let patterns: Punctuated<Pat,Token![,]> = input.parse_terminated(Pat::parse)?;
        for pattern in patterns.into_iter() {
            match pattern {
                Pat::Path(PatPath { path,.. }) => {
                    types.push(path);
                }
                Pat::Struct(PatStruct {
                    path,fields: fields_punctuated,..
                }) => {
                    if fields.is_some() {
                        return Err(Error::new(path.span(),"Expected only one fields pattern!"));
                    }
                    fields = Some(fields_punctuated.into_iter().map(|p| p.member).collect());
                    types.push(path);
                }
                pattern => return Err(Error::new(pattern.span(),"Expected struct pattern!")),}
        }

        Ok(CommonSyntax {
            types,fields: fields.unwrap(),})
    }
}

但这会产生以下编译错误

error: macro expansion ignores token `|` and any following
  --> wizard-common/src/lib.rs:25:17
   |
25 |                 common!(Enum::A,|                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ caused by the macro expansion here
   |
   = note: the usage of `common!` is likely invalid in pattern context

如果我在 panic!(output.to_string()) 之前添加 output.into(),我会在恐慌消息中得到预期的 Enum :: A { a,.. } | Enum :: B { a,.. }。我的代码有什么问题?

依赖版本:

  • syn v1.0.54
  • 引用 v1.0.7

修正: 在引用生成的宏输出周围添加括号可以解决问题,但为什么呢?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...