Macros 写入包含匹配体的宏
我试图浓缩一些重复代码,其结构类似于:Macros 写入包含匹配体的宏,macros,pattern-matching,rust,Macros,Pattern Matching,Rust,我试图浓缩一些重复代码,其结构类似于: match self.foo() { None => self.bar(), Some(MyStruct { foo: x, .. }) => match x { Pattern1 => result, Pattern2 => { block_result } } } 我想这样写: my_macro!( Pattern1 =&g
match self.foo() {
None => self.bar(),
Some(MyStruct { foo: x, .. }) => match x {
Pattern1 => result,
Pattern2 => {
block_result
}
}
}
我想这样写:
my_macro!(
Pattern1 => result,
Pattern2 => {
block_result
}
)
避免重复的None
处理和MyStruct
解构
这看起来应该很简单,因为它本质上只是将宏体替换为匹配表达式,但实际上我找不到任何方法来实现这一点
我尝试按如下方式编写宏:
macro_rules! my_macro (
($($pat:pat => $result:expr,)*) => (
match self.foo() {
None => self.bar(),
Some(MyStruct { foo: x, .. }) => match x {
$(
$pat => $result,
)*
},
}
);
)
但这是失败的,因为匹配臂的RHS可以是表达式或块(并且它也不处理选择性地省略最后一个臂的逗号)。据我所知,没有办法指定宏模式的一部分可以是块或表达式,所以我想不出解决这个问题的方法
理想情况下,我希望这样做,而不必编写复杂的模式来分解匹配体,然后将它们重新粘在一起,但我认为没有任何指示符可以接受匹配表达式的体
您将如何编写此宏?甚至不编写编译器插件也可以吗?我不知道你为什么决定这样做 这将失败,因为匹配臂的RHS可以是表达式或块 在Rust match中,手臂总是表达式,碰巧块也是表达式 宏中有两个问题。首先,正如您所注意到的,宏不能处理省略最后一个逗号的问题。这很容易解决:您只需更改此模式:
$($pat:pat => $result:expr,)*
在这一点上:
$($pat:pat => $result:expr),*
其用途也应改变:
$(
$pat => $result,
)*
到
第二个问题是,除非您在包含self
标识符的范围内(即在方法内部)定义此宏,否则它将不会像您预期的那样工作,因为卫生问题-在self.foo()
和self.bar()中使用的self
标识符
宏主体中的调用与宏扩展站点中的调用不同。作为一般规则,您始终需要将要在宏扩展站点使用的标识符作为参数传递给宏,除非此宏是在已存在这些标识符的范围内定义的
因此,宏的最后一个变体是:
macro_rules! my_macro (
($_self:expr, $($pat:pat => $result:expr),*) => (
match $_self.foo() {
None => $_self.bar(),
Some(MyStruct { foo: x, .. }) => match x {
$(
$pat => $result
),*
},
}
);
)
它的工作原理完全符合你的要求
您可以找到有关宏以及如何编写宏的更多信息。我不知道您为什么决定这样做 这将失败,因为匹配臂的RHS可以是表达式或块 在Rust match中,手臂总是表达式,碰巧块也是表达式 宏中有两个问题。首先,正如您所注意到的,宏不能处理省略最后一个逗号的问题。这很容易解决:您只需更改此模式:
$($pat:pat => $result:expr,)*
在这一点上:
$($pat:pat => $result:expr),*
其用途也应改变:
$(
$pat => $result,
)*
到
第二个问题是,除非您在包含self
标识符的范围内(即在方法内部)定义此宏,否则它将不会像您预期的那样工作,因为卫生问题-在self.foo()
和self.bar()中使用的self
标识符
宏主体中的调用与宏扩展站点中的调用不同。作为一般规则,您始终需要将要在宏扩展站点使用的标识符作为参数传递给宏,除非此宏是在已存在这些标识符的范围内定义的
因此,宏的最后一个变体是:
macro_rules! my_macro (
($_self:expr, $($pat:pat => $result:expr),*) => (
match $_self.foo() {
None => $_self.bar(),
Some(MyStruct { foo: x, .. }) => match x {
$(
$pat => $result
),*
},
}
);
)
它的工作原理完全符合你的要求
您可以找到有关宏以及如何编写宏的更多信息。嗯,我想我误解了收到的错误消息-它似乎无法处理块。需要注意的是,这个版本不允许包含尾随逗号,因此我将
$(,)*
放在模式的末尾。干杯嗯,我猜我误解了我收到的错误消息-它似乎无法处理块。需要注意的是,这个版本不允许包含尾随逗号,因此我将$(,)*
放在模式的末尾。干杯