将模式作为函数参数传递?

Pass a pattern as a function parameter?

我想知道有没有办法将模式作为函数参数传递。

我有:

pub enum KEYWORD {
    assign(ASSIGN),
    symbol(SYMBOL),
    illegal
}

pub enum ASSIGN { /* some enums */ }
pub enum SYMBOL { /* some enums */ }

现在,我知道我可以使用 match! 或我制作的 expect! 宏来匹配我的密钥 l.key() 所以:

macro_rules! expect(($e:expr, $p:pat) => (
    match $e {
        $p => { true },
        _ => { false }
    }
));

expect!(l.key(), KEYWORD::symbol(_));

但是,我需要更多的情况,我需要将 KEYWORD::symbol(_) 作为函数参数传递,例如:

impl l {
    pub fn expect_as_func(&self, KEYWORD) { /* some code */ }
}

l.expect_as_func(KEYWORD::symbol(_));

但是这个 l.expect_as_func(KEYWORD::symbol(_)); 是错误的,因为我使用的不是值,而是模式。

我尝试使用 proc_macroTokenStream

pub fn expect(&mut self, patt: TokenStream) -> bool {
    match &self {
        patt => { true },
        _ => { false }
    }
}

但这也不起作用。

我想说的是,从根本上说,模式不是应该作为函数参数传递给函数的东西:而是应该传递类型的具体实例。

无论如何,如果此任务的上下文确实需要它,您可以将整个函数实现为 TokenSteam,并通过 proc_macro 在内部使用模式。类似于以下内容:

let tokens = quote! {
    pub fn expect(&mut self) -> bool {
        match &self {
            #patt => { true },
            _ => { false }
       }
    }
};

从人体工程学的角度来看,您可以尝试在您的枚举上实现函数 is_assignis_symbolis_illegal

impl KEYWORD {
    fn is_assign(&self) -> bool {
        match self {
            KEYWORD::assign(_) => true,
            _ => false,
        }
    }
    // and so on
}

现在,随着所有这些变得乏味,您可以例如创建一个生成这些函数的宏:

macro_rules! generate_is(($variant: pat, $fn_name: ident) => {
    fn $fn_name(&self) -> bool {
        match self {
            $variant => true,
            _ => false,
        }
    }
});

impl KEYWORD {
    generate_is!(KEYWORD::assign(_), is_assign);
    generate_is!(KEYWORD::symbol(_), is_symbol);
    generate_is!(KEYWORD::illegal, is_illegal);
}

这样,来电者只需说 keyword.is_assign()(或类似的)。

然后,最重要的是,您可以尝试发明一些东西,从您的枚举中自动生成 is_... 函数。 (可能通过程序宏。)