在宏中匹配类似元组的枚举变体,其中枚举类型和变体是元变量:如何编写匹配模式?
Matching tuple-like enum variants in a macro, where enum type and variants are metavariables: how do I write the matching pattern?
简明地放入 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 {}
}
};
}
这只是一种解决方法,但它足够干净。
简明地放入 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 {}
}
};
}
这只是一种解决方法,但它足够干净。