问题描述
简而言之,将其放入Rust代码中,我试图生成这样的模式匹配:
if let Foo::Variant(_) = value {}
// ^^^^^^^^^^^^^^^
在宏中,Foo
(一种类型)和Variant
(一种标识符)都作为元变量传递给宏。在实际用例中,我生成的是match
而不是if let
,并且使用相同枚举的多个变体,但是if let
导致了一个较短的可重现示例。
这适用于简单的枚举:
enum Foo {
Variant,}
macro_rules! match_enum {
(
$value:ident: <$enum:ty>::$variant:ident
) => {
if let <$enum>::$variant = $value {}
};
}
fn main() {
let foo = Foo::Variant;
match_enum!(foo: <Foo>::Variant);
}
这会编译。
但是,当我使枚举变量类似于元组时,它会中断(更改以高亮显示):
enum Foo {
Variant(usize),// ^^^^^^^
}
macro_rules! match_enum {
(
$value:ident: <$enum:ty>::$variant:ident
) => {
if let <$enum>::$variant(_) = $value {}
// ^^^
};
}
fn main() {
let foo = Foo::Variant(0);
// ^^^
match_enum!(foo: <Foo>::Variant);
}
| if let <$enum>::$variant(_) = $value {}
| -----------------^^^ unexpected `(` after qualified path
| |
| the qualified path
...
| match_enum!(foo: <Foo>::Variant);
| --------------------------------- in this macro invocation
我或多或少盲目地尝试了一些变化;其中有$enum::$variant(_)
,<$enum::$variant>(_)
,<$enum::$variant>::(_)
。
这可能吗?我可能使用了错误类型的元变量吗?
This question似乎是相关的,但它侧重于混合单元和元组变体,尚未解决。
解决方法
问题似乎是由$enum
元变量引起的,如以下所示:
macro_rules! match_enum {
(
$value:ident: <$enum:ty>::$variant:ident
) => {
// does not fix the problem
if let <$enum>::Variant(_) = $value {}
// fixes the problem
if let Bar::$variant(_) = $value {}
};
}
当问题发生在语法级别时,我们可以尝试更改所生成代码的语法结构,特别是通过引入类型别名。然后,我们需要确定该类型的范围,以免泄漏出宏:
macro_rules! match_enum {
(
$value:ident: <$enum:ty>::$variant:ident
) => {
{
type Enum = $enum;
if let Enum::Variant(_) = $value {}
}
};
}
这只是一种解决方法,但是足够干净。